diff --git a/korge-foundation/build.gradle.kts b/korge-foundation/build.gradle.kts index fb8cff4520..2e794c4072 100644 --- a/korge-foundation/build.gradle.kts +++ b/korge-foundation/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { //add("commonTestApi", project(":korge-test")) commonTestApi(libs.kotlinx.coroutines.test) commonMainApi(project(":korlibs-time")) + commonMainApi(project(":korlibs-crypto")) } //korlibs.korge.gradle.generate.TemplateGenerator.synchronize(new File(projectDir, "template")) diff --git a/korge-foundation/src/korlibs/crypto/AES.kt b/korge-foundation/src/korlibs/crypto/AES.kt deleted file mode 100644 index b0189e37d9..0000000000 --- a/korge-foundation/src/korlibs/crypto/AES.kt +++ /dev/null @@ -1,217 +0,0 @@ -package korlibs.crypto - -@Suppress("UNUSED_CHANGED_VALUE") -/** - * Based on CryptoJS v3.1.2 - * code.google.com/p/crypto-js - * (c) 2009-2013 by Jeff Mott. All rights reserved. - * code.google.com/p/crypto-js/wiki/License - */ -class AES(val keyWords: IntArray) : Cipher { - override val blockSize: Int get() = BLOCK_SIZE - - private val keySize = keyWords.size - private val numRounds = keySize + 6 - private val ksRows = (numRounds + 1) * 4 - private val keySchedule = IntArray(ksRows).apply { - for (ksRow in indices) { - this[ksRow] = when { - ksRow < keySize -> keyWords[ksRow] - else -> { - var t = this[ksRow - 1] - if (0 == (ksRow % keySize)) { - t = (t shl 8) or (t ushr 24) - t = (SBOX[t.ext8(24)] shl 24) or (SBOX[t.ext8(16)] shl 16) or (SBOX[t.ext8(8)] shl 8) or SBOX[t and 0xff] - t = t xor (RCON[(ksRow / keySize) or 0] shl 24) - } else if (keySize > 6 && ksRow % keySize == 4) { - t = (SBOX[t.ext8(24)] shl 24) or (SBOX[t.ext8(16)] shl 16) or (SBOX[t.ext8(8)] shl 8) or SBOX[t and 0xff] - } - this[ksRow - keySize] xor t - } - } - } - } - private val invKeySchedule = IntArray(ksRows).apply { - for (invKsRow in indices) { - val ksRow = ksRows - invKsRow - val t = if ((invKsRow % 4) != 0) keySchedule[ksRow] else keySchedule[ksRow - 4] - this[invKsRow] = if (invKsRow < 4 || ksRow <= 4) t else INV_SUB_MIX_0[SBOX[t.ext8(24)]] xor INV_SUB_MIX_1[SBOX[t.ext8(16)]] xor INV_SUB_MIX_2[SBOX[t.ext8(8)]] xor INV_SUB_MIX_3[SBOX[t and 0xff]] - } - } - - constructor(key: ByteArray) : this(key.toIntArray()) - - override fun encrypt(data: ByteArray, offset: Int, len: Int) { - for (n in 0 until len step BLOCK_SIZE) encryptBlock(data, offset + n) - } - - override fun decrypt(data: ByteArray, offset: Int, len: Int) { - for (n in 0 until len step BLOCK_SIZE) decryptBlock(data, offset + n) - } - - fun encryptBlock(M: ByteArray, offset: Int) { - this.doCryptBlock(M, offset, this.keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) - } - - fun decryptBlock(M: ByteArray, offset: Int) { - this.doCryptBlock( - M, offset, - this.invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX, - swap13 = true - ) - } - - private fun doCryptBlock( - M: IntArray, offset: Int, keySchedule: IntArray, - SUB_MIX_0: IntArray, SUB_MIX_1: IntArray, SUB_MIX_2: IntArray, SUB_MIX_3: IntArray, SBOX: IntArray, - swap13: Boolean = false - ) { - doCryptBlockInternal(M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX, swap13, - get = { array, o, i -> array[o + i] }, - set = { array, o, i, value -> array[o + i] = value }, - ) - } - - private fun doCryptBlock( - M: ByteArray, offset: Int, keySchedule: IntArray, - SUB_MIX_0: IntArray, SUB_MIX_1: IntArray, SUB_MIX_2: IntArray, SUB_MIX_3: IntArray, SBOX: IntArray, - swap13: Boolean = false - ) { - doCryptBlockInternal(M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX, swap13, - get = { array, o, i -> array.getInt(o + i * 4) }, - set = { array, o, i, value -> array.setInt(o + i * 4, value) }, - ) - } - - private inline fun doCryptBlockInternal( - M: T, offset: Int, keySchedule: IntArray, - SUB_MIX_0: IntArray, SUB_MIX_1: IntArray, SUB_MIX_2: IntArray, SUB_MIX_3: IntArray, SBOX: IntArray, - swap13: Boolean = false, - get: (M: T, offset: Int, index: Int) -> Int, - set: (M: T, offset: Int, index: Int, value: Int) -> Unit, - ) { - val O1 = if (!swap13) 1 else 3 - val O3 = if (!swap13) 3 else 1 - var s0 = get(M, offset, 0) xor keySchedule[0] - var s1 = get(M, offset, O1) xor keySchedule[1] - var s2 = get(M, offset, 2) xor keySchedule[2] - var s3 = get(M, offset, O3) xor keySchedule[3] - var ksRow = 4 - - for (round in 1 until numRounds) { - val t0 = SUB_MIX_0[s0.ext8(24)] xor SUB_MIX_1[s1.ext8(16)] xor SUB_MIX_2[s2.ext8(8)] xor SUB_MIX_3[s3.ext8(0)] xor keySchedule[ksRow++] - val t1 = SUB_MIX_0[s1.ext8(24)] xor SUB_MIX_1[s2.ext8(16)] xor SUB_MIX_2[s3.ext8(8)] xor SUB_MIX_3[s0.ext8(0)] xor keySchedule[ksRow++] - val t2 = SUB_MIX_0[s2.ext8(24)] xor SUB_MIX_1[s3.ext8(16)] xor SUB_MIX_2[s0.ext8(8)] xor SUB_MIX_3[s1.ext8(0)] xor keySchedule[ksRow++] - val t3 = SUB_MIX_0[s3.ext8(24)] xor SUB_MIX_1[s0.ext8(16)] xor SUB_MIX_2[s1.ext8(8)] xor SUB_MIX_3[s2.ext8(0)] xor keySchedule[ksRow++] - s0 = t0; s1 = t1; s2 = t2; s3 = t3 - } - - val t0 = ((SBOX[s0.ext8(24)] shl 24) or (SBOX[s1.ext8(16)] shl 16) or (SBOX[s2.ext8(8)] shl 8) or SBOX[s3.ext8(0)]) xor keySchedule[ksRow++] - val t1 = ((SBOX[s1.ext8(24)] shl 24) or (SBOX[s2.ext8(16)] shl 16) or (SBOX[s3.ext8(8)] shl 8) or SBOX[s0.ext8(0)]) xor keySchedule[ksRow++] - val t2 = ((SBOX[s2.ext8(24)] shl 24) or (SBOX[s3.ext8(16)] shl 16) or (SBOX[s0.ext8(8)] shl 8) or SBOX[s1.ext8(0)]) xor keySchedule[ksRow++] - val t3 = ((SBOX[s3.ext8(24)] shl 24) or (SBOX[s0.ext8(16)] shl 16) or (SBOX[s1.ext8(8)] shl 8) or SBOX[s2.ext8(0)]) xor keySchedule[ksRow++] - - set(M, offset, 0, t0) - set(M, offset, O1, t1) - set(M, offset, 2, t2) - set(M, offset, O3, t3) - } - - companion object { - private val SBOX = IntArray(256) - private val INV_SBOX = IntArray(256) - private val SUB_MIX_0 = IntArray(256) - private val SUB_MIX_1 = IntArray(256) - private val SUB_MIX_2 = IntArray(256) - private val SUB_MIX_3 = IntArray(256) - private val INV_SUB_MIX_0 = IntArray(256) - private val INV_SUB_MIX_1 = IntArray(256) - private val INV_SUB_MIX_2 = IntArray(256) - private val INV_SUB_MIX_3 = IntArray(256) - private val RCON = intArrayOf(0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36) - - private const val BLOCK_SIZE = 16 - - init { - val d = IntArray(256) { if (it >= 128) (it shl 1) xor 0x11b else (it shl 1) } - var x = 0 - var xi = 0 - for (i in 0 until 256) { - var sx = xi xor (xi shl 1) xor (xi shl 2) xor (xi shl 3) xor (xi shl 4) - sx = (sx ushr 8) xor (sx and 0xff) xor 0x63 - SBOX[x] = sx - INV_SBOX[sx] = x - val x2 = d[x] - val x4 = d[x2] - val x8 = d[x4] - ((d[sx] * 0x101) xor (sx * 0x1010100)).also { t -> - SUB_MIX_0[x] = (t shl 24) or (t ushr 8) - SUB_MIX_1[x] = (t shl 16) or (t ushr 16) - SUB_MIX_2[x] = (t shl 8) or (t ushr 24) - SUB_MIX_3[x] = (t shl 0) - } - ((x8 * 0x1010101) xor (x4 * 0x10001) xor (x2 * 0x101) xor (x * 0x1010100)).also { t -> - INV_SUB_MIX_0[sx] = (t shl 24) or (t ushr 8) - INV_SUB_MIX_1[sx] = (t shl 16) or (t ushr 16) - INV_SUB_MIX_2[sx] = (t shl 8) or (t ushr 24) - INV_SUB_MIX_3[sx] = (t shl 0) - } - - if (x == 0) { - x = 1; xi = 1 - } else { - x = x2 xor d[d[d[x8 xor x2]]] - xi = xi xor d[d[xi]] - } - } - } - - fun encryptAesEcb(data: ByteArray, key: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.ECB, padding].encrypt(data) - - fun decryptAesEcb(data: ByteArray, key: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.ECB, padding].decrypt(data) - - fun encryptAesCbc(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.CBC, padding, iv].encrypt(data) - - fun decryptAesCbc(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.CBC, padding, iv].decrypt(data) - - fun encryptAesPcbc(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.PCBC, padding, iv].encrypt(data) - - fun decryptAesPcbc(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.PCBC, padding, iv].decrypt(data) - - fun encryptAesCfb(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.CFB, padding, iv].encrypt(data) - - fun decryptAesCfb(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.CFB, padding, iv].decrypt(data) - - fun encryptAesOfb(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.OFB, padding, iv].encrypt(data) - - fun decryptAesOfb(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.OFB, padding, iv].decrypt(data) - - fun encryptAesCtr(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.CTR, padding, iv].encrypt(data) - - fun decryptAesCtr(data: ByteArray, key: ByteArray, iv: ByteArray, padding: Padding): ByteArray = - AES(key)[CipherMode.CTR, padding, iv].decrypt(data) - } -} - -private fun ByteArray.getu(offset: Int): Int = (this[offset].toInt() and 0xFF) -private inline fun Int.ext8(offset: Int): Int = (this ushr offset) and 0xFF -private fun ByteArray.toIntArray(): IntArray = IntArray(size / 4).also { for (n in it.indices) it[n] = getInt(n * 4) } -private fun ByteArray.getInt(offset: Int): Int = (getu(offset + 0) shl 24) or (getu(offset + 1) shl 16) or (getu(offset + 2) shl 8) or (getu(offset + 3) shl 0) -private fun ByteArray.setInt(offset: Int, value: Int) { - this[offset + 0] = ((value shr 24) and 0xFF).toByte() - this[offset + 1] = ((value shr 16) and 0xFF).toByte() - this[offset + 2] = ((value shr 8) and 0xFF).toByte() - this[offset + 3] = ((value shr 0) and 0xFF).toByte() -} - diff --git a/korge-foundation/src/korlibs/crypto/Cipher.kt b/korge-foundation/src/korlibs/crypto/Cipher.kt deleted file mode 100644 index d659d700ba..0000000000 --- a/korge-foundation/src/korlibs/crypto/Cipher.kt +++ /dev/null @@ -1,19 +0,0 @@ -package korlibs.crypto - -interface Cipher { - val blockSize: Int - fun encrypt(data: ByteArray, offset: Int = 0, len: Int = data.size - offset) - fun decrypt(data: ByteArray, offset: Int = 0, len: Int = data.size - offset) -} - -class CipherWithModeAndPadding(val cipher: Cipher, val mode: CipherMode, val padding: CipherPadding, val iv: ByteArray? = null) { - fun encrypt(data: ByteArray, offset: Int = 0, len: Int = data.size - offset): ByteArray { - return mode.encryptSafe(data.copyOfRange(offset, offset + len), cipher, padding, iv) - } - - fun decrypt(data: ByteArray, offset: Int = 0, len: Int = data.size - offset): ByteArray = - mode.decryptSafe(data.copyOfRange(offset, offset + len), cipher, padding, iv) -} - -fun Cipher.with(mode: CipherMode, padding: CipherPadding, iv: ByteArray? = null): CipherWithModeAndPadding = CipherWithModeAndPadding(this, mode, padding, iv) -operator fun Cipher.get(mode: CipherMode, padding: CipherPadding, iv: ByteArray? = null): CipherWithModeAndPadding = with(mode, padding, iv) diff --git a/korge-foundation/src/korlibs/crypto/CipherMode.kt b/korge-foundation/src/korlibs/crypto/CipherMode.kt deleted file mode 100644 index daf3d8ff7c..0000000000 --- a/korge-foundation/src/korlibs/crypto/CipherMode.kt +++ /dev/null @@ -1,223 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* -import kotlin.experimental.* - -/** - * Symmetric Cipher Mode - */ -interface CipherMode { - companion object { - val ECB: CipherMode get() = CipherModeECB - val CBC: CipherMode get() = CipherModeCBC - val PCBC: CipherMode get() = CipherModePCBC - val CFB: CipherMode get() = CipherModeCFB - val OFB: CipherMode get() = CipherModeOFB - val CTR: CipherMode get() = CipherModeCTR - } - - val name: String - fun encrypt(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray - fun decrypt(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray -} - -private fun Int.nextMultipleOf(multiple: Int) = if (this % multiple == 0) this else (((this / multiple) + 1) * multiple) - -fun CipherMode.encryptSafe(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray { - if (padding == CipherPadding.NoPadding) { - return encrypt(data, cipher, CipherPadding.ZeroPadding, iv).copyOf(data.size) - } - return encrypt(data, cipher, padding, iv) -} -fun CipherMode.decryptSafe(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray { - if (padding == CipherPadding.NoPadding) { - return decrypt(data.copyOf(data.size.nextMultipleOf(cipher.blockSize)), cipher, CipherPadding.ZeroPadding, iv).copyOf(data.size) - } - return decrypt(data, cipher, padding, iv) -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -private object CipherModeECB : CipherModeBase("ECB") { - override fun encrypt(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray { - val pData = padding.add(data, cipher.blockSize) - cipher.encrypt(pData, 0, pData.size) - return pData - } - - override fun decrypt(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray { - cipher.decrypt(data, 0, data.size) - return padding.remove(data) - } -} - -private object CipherModeCBC : CipherModeIV("CBC") { - override fun coreEncrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - for (n in pData.indices step cipher.blockSize) { - arrayxor(pData, n, ivb) - cipher.encrypt(pData, n, cipher.blockSize) - arraycopy(pData, n, ivb, 0, cipher.blockSize) - } - } - - override fun coreDecrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val tempBytes = ByteArray(blockSize) - - for (n in pData.indices step blockSize) { - arraycopy(pData, n, tempBytes, 0, blockSize) - cipher.decrypt(pData, n, blockSize) - arrayxor(pData, n, ivb) - arraycopy(tempBytes, 0, ivb, 0, blockSize) - } - } -} - -private object CipherModePCBC : CipherModeIV("PCBC") { - override fun coreEncrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val plaintext = ByteArray(blockSize) - - for (n in pData.indices step blockSize) { - arraycopy(pData, n, plaintext, 0, blockSize) - arrayxor(pData, n, ivb) - cipher.encrypt(pData, n, cipher.blockSize) - arraycopy(pData, n, ivb, 0, blockSize) - arrayxor(ivb, 0, plaintext) - } - } - - override fun coreDecrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val cipherText = ByteArray(cipher.blockSize) - - for (n in pData.indices step cipher.blockSize) { - arraycopy(pData, n, cipherText, 0, blockSize) - cipher.decrypt(pData, n, cipher.blockSize) - arrayxor(pData, n, ivb) - arraycopy(pData, n, ivb, 0, blockSize) - arrayxor(ivb, 0, cipherText) - } - } -} - -private object CipherModeCFB : CipherModeIV("CFB") { - override fun coreEncrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val cipherText = ByteArray(blockSize) - - cipher.encrypt(ivb) - arraycopy(ivb, 0, cipherText, 0, blockSize) - for (n in pData.indices step blockSize) { - arrayxor(cipherText, 0, blockSize, pData, n) - arraycopy(cipherText, 0, pData, n, blockSize) - - if (n + blockSize < pData.size) { - cipher.encrypt(cipherText) - } - } - } - - override fun coreDecrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val plainText = ByteArray(blockSize) - val cipherText = ByteArray(blockSize) - - cipher.encrypt(ivb) - arraycopy(ivb, 0, cipherText, 0, blockSize) - for (n in pData.indices step blockSize) { - arraycopy(cipherText, 0, plainText, 0, blockSize) - arrayxor(plainText, 0, blockSize, pData, n) - - arraycopy(pData, n, cipherText, 0, blockSize) - arraycopy(plainText, 0, pData, n, blockSize) - if (n + blockSize < pData.size) { - cipher.encrypt(cipherText) - } - } - } -} - -private object CipherModeOFB : CipherModeIVDE("OFB") { - override fun coreCrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val cipherText = ByteArray(blockSize) - cipher.encrypt(ivb) - for (n in pData.indices step blockSize) { - arraycopy(pData, n, cipherText, 0, blockSize) - arrayxor(cipherText, 0, ivb) - arraycopy(cipherText, 0, pData, n, blockSize) - if (n + blockSize < pData.size) { - cipher.encrypt(ivb) - } - } - } -} - -// https://github.com/Jens-G/haxe-crypto/blob/dcf6d994773abba80b0720b2f5e9d5b26de0dbe3/src/com/hurlant/crypto/symmetric/mode/CTRMode.hx -private object CipherModeCTR : CipherModeIVDE("CTR") { - override fun coreCrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) { - val blockSize = cipher.blockSize - val temp = ByteArray(ivb.size) - for (n in pData.indices step blockSize) { - arraycopy(ivb, 0, temp, 0, temp.size) - cipher.encrypt(temp, 0, blockSize) - arrayxor(pData, n, temp) - for (j in blockSize - 1 downTo 0) { - ivb[j]++ - if (ivb[j].toInt() != 0) break - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -private abstract class CipherModeBase(override val name: String) : CipherMode { - override fun toString(): String = name -} - -private abstract class CipherModeIV(name: String) : CipherModeBase(name) { - final override fun encrypt(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray { - val ivb = getIV(iv, cipher.blockSize) - val pData = padding.add(data, cipher.blockSize) - coreEncrypt(pData, cipher, ivb) - return pData - } - - final override fun decrypt(data: ByteArray, cipher: Cipher, padding: Padding, iv: ByteArray?): ByteArray { - val ivb = getIV(iv, cipher.blockSize) - val pData = data.copyOf() - coreDecrypt(pData, cipher, ivb) - return padding.remove(pData) - } - - protected abstract fun coreEncrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) - protected abstract fun coreDecrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) -} - -private abstract class CipherModeIVDE(name: String) : CipherModeIV(name) { - final override fun coreEncrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) = coreCrypt(pData, cipher, ivb) - final override fun coreDecrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) = coreCrypt(pData, cipher, ivb) - - protected abstract fun coreCrypt(pData: ByteArray, cipher: Cipher, ivb: ByteArray) -} - -private fun arrayxor(data: ByteArray, offset: Int, xor: ByteArray) { - for (n in xor.indices) data[offset + n] = data[offset + n] xor xor[n] -} - -private fun arrayxor(data: ByteArray, offset: Int, size: Int, xor: ByteArray, xoroffset: Int) { - for (n in 0 until size) data[offset + n] = data[offset + n] xor xor[xoroffset + n] -} - -private fun getIV(srcIV: ByteArray?, blockSize: Int): ByteArray { - if (srcIV == null) TODO("IV not provided") - if (srcIV.size < blockSize) throw IllegalArgumentException("Wrong IV length: must be $blockSize bytes long") - return srcIV.copyOf(blockSize) - //return ByteArray(blockSize).also { dstIV -> arraycopy(srcIV, 0, dstIV, 0, kotlin.math.min(srcIV.size, dstIV.size)) } -} diff --git a/korge-foundation/src/korlibs/crypto/CipherPadding.kt b/korge-foundation/src/korlibs/crypto/CipherPadding.kt deleted file mode 100644 index 957c2cb77c..0000000000 --- a/korge-foundation/src/korlibs/crypto/CipherPadding.kt +++ /dev/null @@ -1,80 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* -import kotlin.random.Random - -typealias Padding = CipherPadding - -/** - * Symmetric Cipher Padding - */ -abstract class CipherPadding { - companion object { - val NoPadding: CipherPadding get() = CipherPaddingNo - val PKCS7Padding: CipherPadding get() = CipherPaddingPKCS7 - val ANSIX923Padding: CipherPadding get() = CipherPaddingANSIX923 - val ISO10126Padding: CipherPadding get() = CipherPaddingISO10126 - val ZeroPadding: CipherPadding get() = CipherPaddingZero - - fun padding(data: ByteArray, blockSize: Int, padding: Padding): ByteArray = padding.add(data, blockSize) - fun removePadding(data: ByteArray, padding: Padding): ByteArray = padding.remove(data) - } - - fun add(data: ByteArray, blockSize: Int): ByteArray { - //padding(data, blockSize, this) - val paddingSize = paddingSize(data.size, blockSize) - val result = ByteArray(data.size + paddingSize) - arraycopy(data, 0, result, 0, data.size) - addInternal(result, data.size, paddingSize) - return result - } - fun remove(data: ByteArray): ByteArray { - val result = data.copyOf() - val size = removeInternal(data) - return result.copyOf(size) - } - - protected open fun paddingSize(dataSize: Int, blockSize: Int): Int = blockSize - dataSize % blockSize - protected open fun addInternal(result: ByteArray, dataSize: Int, paddingSize: Int) : Unit = Unit - protected open fun removeInternal(data: ByteArray) : Int = data.size - (data[data.size - 1].toInt() and 0xFF) -} - -private object CipherPaddingNo : CipherPadding() { - override fun paddingSize(dataSize: Int, blockSize: Int): Int { - if (dataSize % blockSize != 0) { - throw IllegalArgumentException("Data ($dataSize) is not multiple of ${blockSize}, and padding was set to $NoPadding") - } - return 0 - } - override fun addInternal(result: ByteArray, dataSize: Int, paddingSize: Int) = Unit - override fun removeInternal(data: ByteArray): Int = data.size -} -private object CipherPaddingPKCS7 : CipherPadding() { - override fun addInternal(result: ByteArray, dataSize: Int, paddingSize: Int) { - for (i in dataSize until result.size) result[i] = paddingSize.toByte() - } -} -private object CipherPaddingANSIX923 : CipherPadding() { - override fun addInternal(result: ByteArray, dataSize: Int, paddingSize: Int) { - result[result.size - 1] = paddingSize.toByte() - } -} -private object CipherPaddingISO10126 : CipherPadding() { - override fun addInternal(result: ByteArray, dataSize: Int, paddingSize: Int) { - val randomBytes = Random.nextBytes(paddingSize) - randomBytes[paddingSize - 1] = paddingSize.toByte() - arraycopy(randomBytes, 0, result, dataSize, randomBytes.size) - } -} -private object CipherPaddingZero : CipherPadding() { - override fun removeInternal(data: ByteArray): Int { - var paddingSize = 0 - for (i in data.size - 1 downTo 0) { - if (data[i].toInt() != 0) { - break - } - ++paddingSize - } - return data.size - paddingSize - } -} diff --git a/korge-foundation/src/korlibs/crypto/HMAC.kt b/korge-foundation/src/korlibs/crypto/HMAC.kt deleted file mode 100644 index b617d9fb61..0000000000 --- a/korge-foundation/src/korlibs/crypto/HMAC.kt +++ /dev/null @@ -1,44 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* - -class HMAC { - - companion object { - fun hmacSHA1(key: ByteArray, data: ByteArray): Hash = hmac(key, data, SHA1()) - - fun hmacSHA256(key: ByteArray, data: ByteArray): Hash = hmac(key, data, SHA256()) - - fun hmacSHA512(key: ByteArray, data: ByteArray): Hash = hmac(key, data, SHA512()) - - fun hmacMD5(key: ByteArray, data: ByteArray): Hash = hmac(key, data, MD5()) - - internal fun hmac(key: ByteArray, data: ByteArray, hasher: Hasher): Hash { - var key = key - val blockSize = hasher.chunkSize - if (key.size > blockSize) { - hasher.reset() - hasher.update(key) - key = hasher.digest().bytes - } - if (key.size < blockSize) { - val newKey = ByteArray(blockSize) - arraycopy(key, 0, newKey, 0, key.size) - key = newKey - } - - val oKeyPad = ByteArray(blockSize) { (0x5c xor key[it].toInt()).toByte() } - val iKeyPad = ByteArray(blockSize) { (0x36 xor key[it].toInt()).toByte() } - - hasher.reset() - hasher.update(iKeyPad) - hasher.update(data) - val h1 = hasher.digest().bytes - - hasher.reset() - hasher.update(oKeyPad) - hasher.update(h1) - return hasher.digest() - } - } -} diff --git a/korge-foundation/src/korlibs/crypto/Hasher.kt b/korge-foundation/src/korlibs/crypto/Hasher.kt deleted file mode 100644 index 969aeae8b7..0000000000 --- a/korge-foundation/src/korlibs/crypto/Hasher.kt +++ /dev/null @@ -1,116 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.Base64 -import korlibs.encoding.Hex -import korlibs.memory.* -import kotlin.math.min - -open class HasherFactory(val name: String, val create: () -> Hasher) { - operator fun invoke(): Hasher = create() - fun digest(data: ByteArray): Hash = create().also { it.update(data, 0, data.size) }.digest() - - inline fun digest(temp: ByteArray = ByteArray(0x1000), readBytes: (data: ByteArray) -> Int): Hash = - this.create().also { - while (true) { - val count = readBytes(temp) - if (count <= 0) break - it.update(temp, 0, count) - } - }.digest() - - override fun toString(): String = "HasherFactory($name)" -} - -abstract class NonCoreHasher(chunkSize: Int, digestSize: Int, name: String) : Hasher(chunkSize, digestSize, name) { - abstract override fun reset(): Hasher - abstract override fun update(data: ByteArray, offset: Int, count: Int): Hasher - abstract override fun digestOut(out: ByteArray): Unit - - override fun coreReset() = TODO() - override fun corePadding(totalWritten: Long): ByteArray = TODO() - override fun coreUpdate(chunk: ByteArray) = TODO() - override fun coreDigest(out: ByteArray) = TODO() -} - -/** - * [chunkSize] in bytes - */ -abstract class Hasher(val chunkSize: Int, val digestSize: Int, val name: String) { - /** - * In bits - */ - val blockSize: Int get() = chunkSize * 8 - - private val chunk = ByteArray(chunkSize) - private var writtenInChunk = 0 - protected var totalWritten = 0L - - open fun reset(): Hasher { - coreReset() - writtenInChunk = 0 - totalWritten = 0L - return this - } - - open fun update(data: ByteArray, offset: Int, count: Int): Hasher { - var curr = offset - var left = count - while (left > 0) { - val remainingInChunk = chunkSize - writtenInChunk - val toRead = min(remainingInChunk, left) - arraycopy(data, curr, chunk, writtenInChunk, toRead) - left -= toRead - curr += toRead - writtenInChunk += toRead - if (writtenInChunk >= chunkSize) { - writtenInChunk -= chunkSize - coreUpdate(chunk) - } - } - totalWritten += count - return this - } - - open fun digestOut(out: ByteArray) { - val pad = corePadding(totalWritten) - var padPos = 0 - while (padPos < pad.size) { - val padSize = chunkSize - writtenInChunk - arraycopy(pad, padPos, chunk, writtenInChunk, padSize) - coreUpdate(chunk) - writtenInChunk = 0 - padPos += padSize - } - - coreDigest(out) - coreReset() - } - - protected abstract fun coreReset() - protected abstract fun corePadding(totalWritten: Long): ByteArray - protected abstract fun coreUpdate(chunk: ByteArray) - protected abstract fun coreDigest(out: ByteArray) - - fun update(data: ByteArray) = update(data, 0, data.size) - fun digest(): Hash = Hash(ByteArray(digestSize).also { digestOut(it) }) - - override fun toString(): String = "Hasher($name)" -} - -class Hash(val bytes: ByteArray) { - companion object { - fun fromHex(hex: String): Hash = Hash(Hex.decode(hex)) - fun fromBase64(base64: String): Hash = Hash(Base64.decodeIgnoringSpaces(base64)) - } - val base64 get() = Base64.encode(bytes) - val base64Url get() = Base64.encode(bytes, true) - val hex get() = Hex.encode(bytes) - val hexLower get() = Hex.encodeLower(bytes) - val hexUpper get() = Hex.encodeUpper(bytes) - - override fun equals(other: Any?): Boolean = other is Hash && this.bytes.contentEquals(other.bytes) - override fun hashCode(): Int = bytes.contentHashCode() - override fun toString(): String = hexLower -} - -fun ByteArray.hash(algo: HasherFactory): Hash = algo.digest(this) diff --git a/korge-foundation/src/korlibs/crypto/MD4.kt b/korge-foundation/src/korlibs/crypto/MD4.kt deleted file mode 100644 index 7321ab2a9a..0000000000 --- a/korge-foundation/src/korlibs/crypto/MD4.kt +++ /dev/null @@ -1,72 +0,0 @@ -package korlibs.crypto - -class MD4 : Hasher(chunkSize = 64, digestSize = 16, "MD4") { - - companion object : HasherFactory("MD4", { MD4() }) { - private val S = intArrayOf(3, 7, 11, 19, 3, 5, 9, 13, 3, 9, 11, 15) - private val R3 = listOf(0, 2, 1, 3) - } - - private val r = IntArray(4) - private val o = IntArray(4) - private val b = IntArray(16) - - init { - coreReset() - } - - override fun coreReset() { - r[0] = 0x67452301 - r[1] = 0xEFCDAB89.toInt() - r[2] = 0x98BADCFE.toInt() - r[3] = 0x10325476 - } - - override fun coreUpdate(chunk: ByteArray) { - for (j in 0 until 64) b[j ushr 2] = (chunk[j].toInt() shl 24) or (b[j ushr 2] ushr 8) - for (j in 0 until 4) o[j] = r[j] - for (j in 0 until 48) { - val d16 = j / 16 - val f = when (d16) { - 0 -> (r[1] and r[2]) or (r[1].inv() and r[3]) - 1 -> (r[1] and r[2]) or (r[1] and r[3]) or (r[2] and r[3]) - 2 -> r[1] xor r[2] xor r[3] - else -> 0 - } - - val bi = when (d16) { - 0 -> j - 1 -> j % 16 / 4 + j * 4 % 16 - 2 -> R3[j % 16 / 4] + 4 * R3[j % 4] - else -> 0 - } - val t = when (d16) { - 0 -> 0 - 1 -> 0x5a827999 - 2 -> 0x6ed9eba1 - else -> 0 - } - val temp = (r[0] + f + b[bi] + t).rotateLeft(S[(d16 shl 2) or (j and 3)]) - r[0] = r[3] - r[3] = r[2] - r[2] = r[1] - r[1] = temp - } - for (j in 0 until 4) r[j] += o[j] - } - - override fun corePadding(totalWritten: Long): ByteArray { - val numberOfBlocks = ((totalWritten + 8) / chunkSize) + 1 - val totalWrittenBits = totalWritten * 8 - return ByteArray(((numberOfBlocks * chunkSize) - totalWritten).toInt()).apply { - this[0] = 0x80.toByte() - for (i in 0 until 8) this[this.size - 8 + i] = (totalWrittenBits ushr (8 * i)).toByte() - } - } - - override fun coreDigest(out: ByteArray) { - for (it in 0 until 16) out[it] = (r[it / 4] ushr ((it % 4) * 8)).toByte() - } -} - -fun ByteArray.md4() = hash(MD4) diff --git a/korge-foundation/src/korlibs/crypto/MD5.kt b/korge-foundation/src/korlibs/crypto/MD5.kt deleted file mode 100644 index 7db7fd775f..0000000000 --- a/korge-foundation/src/korlibs/crypto/MD5.kt +++ /dev/null @@ -1,69 +0,0 @@ -package korlibs.crypto - -import kotlin.math.abs -import kotlin.math.sin - -class MD5 : Hasher(chunkSize = 64, digestSize = 16, "MD5") { - companion object : HasherFactory("MD5", { MD5() }) { - private val S = intArrayOf(7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21) - private val T = IntArray(64) { ((1L shl 32) * abs(sin(1.0 + it))).toLong().toInt() } - } - - private val r = IntArray(4) - private val o = IntArray(4) - private val b = IntArray(16) - - init { - coreReset() - } - - override fun coreReset() { - r[0] = 0x67452301 - r[1] = 0xEFCDAB89.toInt() - r[2] = 0x98BADCFE.toInt() - r[3] = 0x10325476 - } - - override fun coreUpdate(chunk: ByteArray) { - for (j in 0 until 64) b[j ushr 2] = (chunk[j].toInt() shl 24) or (b[j ushr 2] ushr 8) - for (j in 0 until 4) o[j] = r[j] - for (j in 0 until 64) { - val d16 = j / 16 - val f = when (d16) { - 0 -> (r[1] and r[2]) or (r[1].inv() and r[3]) - 1 -> (r[1] and r[3]) or (r[2] and r[3].inv()) - 2 -> r[1] xor r[2] xor r[3] - 3 -> r[2] xor (r[1] or r[3].inv()) - else -> 0 - } - val bi = when (d16) { - 0 -> j - 1 -> (j * 5 + 1) and 0x0F - 2 -> (j * 3 + 5) and 0x0F - 3 -> (j * 7) and 0x0F - else -> 0 - } - val temp = r[1] + (r[0] + f + b[bi] + T[j]).rotateLeft(S[(d16 shl 2) or (j and 3)]) - r[0] = r[3] - r[3] = r[2] - r[2] = r[1] - r[1] = temp - } - for (j in 0 until 4) r[j] += o[j] - } - - override fun corePadding(totalWritten: Long): ByteArray { - val numberOfBlocks = ((totalWritten + 8) / chunkSize) + 1 - val totalWrittenBits = totalWritten * 8 - return ByteArray(((numberOfBlocks * chunkSize) - totalWritten).toInt()).apply { - this[0] = 0x80.toByte() - for (i in 0 until 8) this[this.size - 8 + i] = (totalWrittenBits ushr (8 * i)).toByte() - } - } - - override fun coreDigest(out: ByteArray) { - for (it in 0 until 16) out[it] = (r[it / 4] ushr ((it % 4) * 8)).toByte() - } -} - -fun ByteArray.md5() = hash(MD5) diff --git a/korge-foundation/src/korlibs/crypto/PBKDF2.kt b/korge-foundation/src/korlibs/crypto/PBKDF2.kt deleted file mode 100644 index 6a084370a2..0000000000 --- a/korge-foundation/src/korlibs/crypto/PBKDF2.kt +++ /dev/null @@ -1,56 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* - -class PBKDF2 { - companion object { - fun pbkdf2WithHmacSHA1(password: ByteArray, salt: ByteArray, iterationCount: Int, keySizeInBits: Int): Hash = - pbkdf2(password, salt, iterationCount, keySizeInBits, SHA1()) - - fun pbkdf2WithHmacSHA256(password: ByteArray, salt: ByteArray, iterationCount: Int, keySizeInBits: Int): Hash = - pbkdf2(password, salt, iterationCount, keySizeInBits, SHA256()) - - fun pbkdf2WithHmacSHA512(password: ByteArray, salt: ByteArray, iterationCount: Int, keySizeInBits: Int): Hash = - pbkdf2(password, salt, iterationCount, keySizeInBits, SHA512()) - - private fun Int.toByteArray(out: ByteArray = ByteArray(4)): ByteArray { - out[0] = (this shr 24 and 0xff).toByte() - out[1] = (this shr 16 and 0xff).toByte() - out[2] = (this shr 8 and 0xff).toByte() - out[3] = (this and 0xff).toByte() - return out - } - - fun pbkdf2(password: ByteArray, salt: ByteArray, iterationCount: Int, keySizeInBits: Int, hasher: Hasher): Hash { - val hLen = hasher.digestSize - val blockSize = keySizeInBits / hLen - val outSize = keySizeInBits / 8 - var offset = 0 - val result = ByteArray(outSize) - val t = ByteArray(hLen) - val i32be = ByteArray(4) - val uv = ByteArray(salt.size + i32be.size) - gen@ for (i in 1 .. blockSize) { - t.fill(0) - i.toByteArray(i32be) - arraycopy(salt, 0, uv, 0, salt.size) - arraycopy(i32be, 0, uv, salt.size, i32be.size) - var u = uv - for (c in 1 .. iterationCount) { - u = HMAC.hmac(password, u, hasher).bytes - hasher.reset() - for (m in u.indices) { - t[m] = (t[m].toInt() xor u[m].toInt()).toByte() - } - } - for (b in t) { - result[offset++] = b - if (offset >= outSize) { - break@gen - } - } - } - return Hash(result) - } - } -} diff --git a/korge-foundation/src/korlibs/crypto/SHA.kt b/korge-foundation/src/korlibs/crypto/SHA.kt deleted file mode 100644 index 289d0a1305..0000000000 --- a/korge-foundation/src/korlibs/crypto/SHA.kt +++ /dev/null @@ -1,16 +0,0 @@ -package korlibs.crypto - -abstract class SHA(chunkSize: Int, digestSize: Int, name: String = "SHA${digestSize * 8}") : Hasher(chunkSize, digestSize, name) { - override fun corePadding(totalWritten: Long): ByteArray { - val tail = totalWritten % 64 - val padding = if (64 - tail >= 9) 64 - tail else 128 - tail - val pad = ByteArray(padding.toInt()).also { it[0] = 0x80.toByte() } - val bits = (totalWritten * 8) - for (i in 0 until 8) pad[pad.size - 1 - i] = ((bits ushr (8 * i)) and 0xFF).toByte() - return pad - } - - protected fun ByteArray.readU8(o: Int): Int = this[o].toInt() and 0xFF - protected fun ByteArray.readS32_be(o: Int): Int = - (readU8(o + 3) shl 0) or (readU8(o + 2) shl 8) or (readU8(o + 1) shl 16) or (readU8(o + 0) shl 24) -} diff --git a/korge-foundation/src/korlibs/crypto/SHA1.kt b/korge-foundation/src/korlibs/crypto/SHA1.kt deleted file mode 100644 index edf4a2e072..0000000000 --- a/korge-foundation/src/korlibs/crypto/SHA1.kt +++ /dev/null @@ -1,68 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* -import kotlin.rotateLeft - -class SHA1 : SHA(chunkSize = 64, digestSize = 20, name = "SHA1") { - companion object : HasherFactory("SHA1", { SHA1() }) { - private val H = intArrayOf( - 0x67452301L.toInt(), - 0xEFCDAB89L.toInt(), - 0x98BADCFEL.toInt(), - 0x10325476L.toInt(), - 0xC3D2E1F0L.toInt() - ) - - private const val K0020: Int = 0x5A827999L.toInt() - private const val K2040: Int = 0x6ED9EBA1L.toInt() - private const val K4060: Int = 0x8F1BBCDCL.toInt() - private const val K6080: Int = 0xCA62C1D6L.toInt() - } - - private val w = IntArray(80) - private val h = IntArray(5) - - override fun coreReset() { arraycopy(H, 0, h, 0, 5) } - - init { - coreReset() - } - - override fun coreUpdate(chunk: ByteArray) { - for (j in 0 until 16) w[j] = chunk.readS32_be(j * 4) - for (j in 16 until 80) w[j] = (w[j - 3] xor w[j - 8] xor w[j - 14] xor w[j - 16]).rotateLeft(1) - - var a = h[0] - var b = h[1] - var c = h[2] - var d = h[3] - var e = h[4] - - for (j in 0 until 80) { - val temp = a.rotateLeft(5) + e + w[j] + when (j / 20) { - 0 -> ((b and c) or ((b.inv()) and d)) + K0020 - 1 -> (b xor c xor d) + K2040 - 2 -> ((b and c) xor (b and d) xor (c and d)) + K4060 - else -> (b xor c xor d) + K6080 - } - - e = d - d = c - c = b.rotateLeft(30) - b = a - a = temp - } - - h[0] += a - h[1] += b - h[2] += c - h[3] += d - h[4] += e - } - - override fun coreDigest(out: ByteArray) { - for (n in out.indices) out[n] = (h[n / 4] ushr (24 - 8 * (n % 4))).toByte() - } -} - -fun ByteArray.sha1() = hash(SHA1) diff --git a/korge-foundation/src/korlibs/crypto/SHA256.kt b/korge-foundation/src/korlibs/crypto/SHA256.kt deleted file mode 100644 index df1c1ca2df..0000000000 --- a/korge-foundation/src/korlibs/crypto/SHA256.kt +++ /dev/null @@ -1,79 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* -import kotlin.rotateRight - -class SHA256 : SHA(chunkSize = 64, digestSize = 32) { - companion object : HasherFactory("SHA256", { SHA256() }) { - private val H = intArrayOf( - 0x6a09e667, -0x4498517b, 0x3c6ef372, -0x5ab00ac6, - 0x510e527f, -0x64fa9774, 0x1f83d9ab, 0x5be0cd19 - ) - - private val K = intArrayOf( - 0x428a2f98, 0x71374491, -0x4a3f0431, -0x164a245b, - 0x3956c25b, 0x59f111f1, -0x6dc07d5c, -0x54e3a12b, - -0x27f85568, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, -0x7f214e02, -0x6423f959, -0x3e640e8c, - -0x1b64963f, -0x1041b87a, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - -0x67c1aeae, -0x57ce3993, -0x4ffcd838, -0x40a68039, - -0x391ff40d, -0x2a586eb9, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, -0x7e3d36d2, -0x6d8dd37b, - -0x5d40175f, -0x57e599b5, -0x3db47490, -0x3893ae5d, - -0x2e6d17e7, -0x2966f9dc, -0xbf1ca7b, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, -0x7b3787ec, -0x7338fdf8, - -0x6f410006, -0x5baf9315, -0x41065c09, -0x398e870e - ) - } - - - private val h = IntArray(8) - private val r = IntArray(8) - private val w = IntArray(64) - - init { - coreReset() - } - - override fun coreReset() { arraycopy(H, 0, h, 0, 8) } - - override fun coreUpdate(chunk: ByteArray) { - arraycopy(h, 0, r, 0, 8) - - for (j in 0 until 16) w[j] = chunk.readS32_be(j * 4) - for (j in 16 until 64) { - val s0 = w[j - 15].rotateRight(7) xor w[j - 15].rotateRight(18) xor w[j - 15].ushr(3) - val s1 = w[j - 2].rotateRight(17) xor w[j - 2].rotateRight(19) xor w[j - 2].ushr(10) - w[j] = w[j - 16] + s0 + w[j - 7] + s1 - } - - for (j in 0 until 64) { - val s1 = r[4].rotateRight(6) xor r[4].rotateRight(11) xor r[4].rotateRight(25) - val ch = r[4] and r[5] xor (r[4].inv() and r[6]) - val t1 = r[7] + s1 + ch + K[j] + w[j] - val s0 = r[0].rotateRight(2) xor r[0].rotateRight(13) xor r[0].rotateRight(22) - val maj = r[0] and r[1] xor (r[0] and r[2]) xor (r[1] and r[2]) - val t2 = s0 + maj - r[7] = r[6] - r[6] = r[5] - r[5] = r[4] - r[4] = r[3] + t1 - r[3] = r[2] - r[2] = r[1] - r[1] = r[0] - r[0] = t1 + t2 - - } - for (j in 0 until 8) h[j] += r[j] - } - - override fun coreDigest(out: ByteArray) { - for (n in out.indices) out[n] = (h[n / 4] ushr (24 - 8 * (n % 4))).toByte() - } -} - -fun ByteArray.sha256() = hash(SHA256) diff --git a/korge-foundation/src/korlibs/crypto/SHA3.kt b/korge-foundation/src/korlibs/crypto/SHA3.kt deleted file mode 100644 index a49d5fc0e1..0000000000 --- a/korge-foundation/src/korlibs/crypto/SHA3.kt +++ /dev/null @@ -1,656 +0,0 @@ -/* -@file:Suppress("NAME_SHADOWING") - -package korlibs.crypto - -import korlibs.encoding.Hex - -@KryptoExperimental -class SHA3_256 : SHA3(16, 256) { -} - -@KryptoExperimental -abstract class SHA3 internal constructor(chunkSize: Int, val digestSizeBits: Int) : Hasher(chunkSize, digestSizeBits / 8) { - private lateinit var keccak: SHA3Impl.Keccak - - init { - coreReset() - } - - // @TODO: Actual reset - override fun coreReset() { - keccak = SHA3Impl.Keccak(digestSizeBits, SHA3Impl.KECCAK_PADDING, digestSizeBits) - } - - override fun corePadding(totalWritten: Long): ByteArray { - //TODO("Not yet implemented") - //return ByteArray(0) - keccak.finalize() - return ByteArray(0) - } - - override fun coreUpdate(chunk: ByteArray) { - keccak.update(chunk.asUByteArray()) - } - - override fun coreDigest(out: ByteArray) { - val data = keccak.digest() - data.copyInto(out.asUByteArray()) - } -} - -// https://github.com/emn178/js-sha3/blob/master/src/sha3.js -/** - * [js-sha3]{@link https://github.com/emn178/js-sha3} - * - * @version 0.8.0 - * @author Chen, Yi-Cyuan [emn178@gmail.com] - * @copyright Chen, Yi-Cyuan 2015-2018 - * @license MIT - */ - -@Suppress("unused") -@OptIn(ExperimentalUnsignedTypes::class) -internal object SHA3Impl { - val SHAKE_PADDING = intArrayOf(31, 7936, 2031616, 520093696) - val CSHAKE_PADDING = intArrayOf(4, 1024, 262144, 67108864) - val KECCAK_PADDING = intArrayOf(1, 256, 65536, 16777216) - val PADDING = intArrayOf(6, 1536, 393216, 100663296) - val SHIFT = intArrayOf(0, 8, 16, 24) - val RC = uintArrayOf(1U, 0U, 32898U, 0U, 32906U, 2147483648U, 2147516416U, 2147483648U, 32907U, 0U, 2147483649U, - 0U, 2147516545U, 2147483648U, 32777U, 2147483648U, 138U, 0U, 136U, 0U, 2147516425U, 0U, - 2147483658U, 0U, 2147516555U, 0U, 139U, 2147483648U, 32905U, 2147483648U, 32771U, - 2147483648U, 32770U, 2147483648U, 128U, 2147483648U, 32778U, 0U, 2147483658U, 2147483648U, - 2147516545U, 2147483648U, 32896U, 2147483648U, 2147483649U, 0U, 2147516424U, 2147483648U - ) - val OUTPUT_TYPES = listOf("hex", "buffer", "arrayBuffer", "array", "digest") - val BITS = intArrayOf(224, 256, 384, 512) - val SHAKE_BITS = intArrayOf(128, 256) - val CSHAKE_BYTEPAD = mapOf( - "128" to 168, - "256" to 136 - ) - - /* - fun createOutputMethod(bits: Int, padding: Int, outputType: String) { - return { message -> - return Keccak(bits, padding, bits).update(message)[outputType](); - } - } - fun createShakeOutputMethod(bits: Int, padding: Int, outputType: String) { - return { message, outputBits -> - return Keccak(bits, padding, outputBits).update(message)[outputType](); - } - } - fun createCshakeOutputMethod(bits: Int, padding: Int, outputType: String) { - return { message, outputBits, n, s -> - return methods['cshake' + bits].update(message, outputBits, n, s)[outputType](); - } - } - fun createKmacOutputMethod(bits: Int, padding: Int, outputType: String) { - return { key, message, outputBits, s -> - return methods['kmac' + bits].update(key, message, outputBits, s)[outputType](); - } - } - fun createOutputMethods(method, createMethod, bits, padding) { - for (i in 0 until OUTPUT_TYPES.length) { - var type = OUTPUT_TYPES[i]; - method[type] = createMethod(bits, padding, type); - } - return method; - }; - interface Sha3Method { - fun create() - fun update(message: UByteArray) - } - fun createMethod (bits: Int, padding: Int) { - var method = createOutputMethod(bits, padding, "hex"); - method.create = function () { - return new Keccak(bits, padding, bits); - }; - method.update = function (message) { - return method.create().update(message); - }; - return createOutputMethods(method, createOutputMethod, bits, padding); - }; - fun createShakeMethod(bits: Int, padding: Int) { - var method = createShakeOutputMethod(bits, padding, "hex"); - method.create = function (outputBits) { - return new Keccak(bits, padding, outputBits); - }; - method.update = function (message, outputBits) { - return method.create(outputBits).update(message); - }; - return createOutputMethods(method, createShakeOutputMethod, bits, padding); - }; - fun createCshakeMethod(bits: Int, padding: Int) { - val w = CSHAKE_BYTEPAD[bits]; - val method = createCshakeOutputMethod(bits, padding, "hex"); - method.create = { outputBits, n, s -> - if (!n && !s) { - return methods['shake' + bits].create(outputBits); - } else { - return Keccak(bits, padding, outputBits).bytepad([n, s], w); - } - }; - method.update = { message, outputBits, n, s -> - return method.create(outputBits, n, s).update(message); - }; - return createOutputMethods(method, createCshakeOutputMethod, bits, padding); - }; - fun createKmacMethod(bits: Int, padding: Int) { - val w = CSHAKE_BYTEPAD[bits]; - val method = createKmacOutputMethod(bits, padding, "hex"); - method.create = { key, outputBits, s, - return Kmac(bits, padding, outputBits).bytepad(['KMAC', s], w).bytepad([key], w); - }; - method.update = { key, message, outputBits, s -> - return method.create(key, outputBits, s).update(message); - }; - return createOutputMethods(method, createKmacOutputMethod, bits, padding); - }; - class SHA3(val padding: Int, val bits: Int) { - init { - assert(padding in PADDING) - assert(padding in PADDING) - } - } - data class Algo(val name: String, val padding: IntArray, val bits: IntArray, val createMethod: Any) - val algorithms = listOf( - Algo(name = "keccak", padding = KECCAK_PADDING, bits = BITS, createMethod = createMethod), - Algo(name = "sha3", padding = PADDING, bits = BITS, createMethod = createMethod), - Algo(name = "shake", padding = SHAKE_PADDING, bits = SHAKE_BITS, createMethod = createShakeMethod), - Algo(name = "cshake", padding = CSHAKE_PADDING, bits = SHAKE_BITS, createMethod = createCshakeMethod), - Algo(name = "kmac", padding = CSHAKE_PADDING, bits = SHAKE_BITS, createMethod = createKmacMethod) - ) - var methods = LinkedHashMap() - var methodNames = arrayListOf() - init { - for (i in 0 until algorithms.size) { - val algorithm = algorithms[i]; - val bits = algorithm.bits; - for (j in 0 until bits.size) { - val methodName = algorithm.name + '_' + bits[j]; - methodNames.add(methodName); - methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding); - if (algorithm.name != "sha3") { - val newMethodName = algorithm.name + bits[j]; - methodNames.add(newMethodName); - methods[newMethodName] = methods[methodName]; - } - } - } - } - */ - - open class Keccak(bits: Int, var padding: IntArray, var outputBits: Int) { - private var blocks = IntArray(50) - private var buffer = UByteArray(bits / 8) - private var s = IntArray(50) - private var reset = true - private var finalized = false - private var block = 0 - private var start = 0 - private var blockCount = (1600 - (bits shl 1)) shr 5 - private var byteCount = this.blockCount shl 2 - private var outputBlocks = outputBits shr 5 - private var extraBytes = (outputBits and 31) shr 3 - private var lastByteIndex: Int = 0 - - fun update(message: UByteArray): Keccak { - if (this.finalized) { - error("finalize already called") - } - val blocks = this.blocks - val byteCount = this.byteCount - val length: Int = message.size - val blockCount = this.blockCount - var index = 0 - val s = this.s - var i: Int - - while (index < length) { - if (this.reset) { - this.reset = false - blocks[0] = this.block - i = 1 - while (i < blockCount + 1) { - blocks[i] = 0 - ++i - } - } - - i = this.start - while (index < length && i < byteCount) { - blocks[i shr 2] = blocks[i shr 2] or (message[index].toInt() shl SHIFT[i++ and 3]) - ++index - } - - this.lastByteIndex = i - if (i >= byteCount) { - this.start = i - byteCount - this.block = blocks[blockCount] - i = 0 - while (i < blockCount) { - s[i] = s[i] xor blocks[i] - ++i - } - f(s) - this.reset = true - } else { - this.start = i - } - } - return this - } - - fun encode(x: Int, right: Boolean = false): Int { - var o = x and 255 - var n = 1 - // @TODO: Optimize - val bytes = arrayListOf(o) - var x = x shr 8 - o = x and 255 - while (o > 0) { - bytes.add(0, o) - x = x shr 8 - o = x and 255 - ++n - } - if (right) { - bytes.add(n) - } else { - bytes.add(0, n) - } - // @TODO: Optimize - this.update(bytes.map { it.toByte() }.toByteArray().asUByteArray()) - return bytes.size - } - - fun encodeString(str: UByteArray): Int { - var bytes: Int = str.size - bytes += this.encode(bytes * 8, false) - this.update(str) - return bytes - } - - fun bytepad(strs: List, w: Int): Keccak { - var bytes = this.encode(w, false) - for (element in strs) bytes += this.encodeString(element) - this.update(UByteArray(w - bytes % w)) - return this - } - - open fun finalize() { - if (this.finalized) return - this.finalized = true - val blocks = this.blocks - val i = this.lastByteIndex - val blockCount = this.blockCount - val s = this.s - blocks[i shr 2] = blocks[i shr 2] or this.padding[i and 3] - if (this.lastByteIndex == this.byteCount) { - blocks[0] = blocks[blockCount] - for (i in 1 until blockCount + 1) blocks[i] = 0 - } - blocks[blockCount - 1] = blocks[blockCount - 1] or 0x80000000.toInt() - for (i in 0 until blockCount) s[i] = s[i] xor blocks[i] - f(s) - } - - fun hex(): String { - this.finalize() - val HEX_CHARS = Hex.DIGITS_LOWER - - val blockCount = this.blockCount - val s = this.s - val outputBlocks = this.outputBlocks - val extraBytes = this.extraBytes - var i = 0 - var j = 0 - val hex = StringBuilder() - while (j < outputBlocks) { - i = 0 - while (i < blockCount && j < outputBlocks) { - val block = s[i] - hex.append(HEX_CHARS[(block shr 4) and 0x0F]) - hex.append(HEX_CHARS[block and 0x0F]) - hex.append(HEX_CHARS[(block shr 12) and 0x0F]) - hex.append(HEX_CHARS[(block shr 8) and 0x0F]) - hex.append(HEX_CHARS[(block shr 20) and 0x0F]) - hex.append(HEX_CHARS[(block shr 16) and 0x0F]) - hex.append(HEX_CHARS[(block shr 28) and 0x0F]) - hex.append(HEX_CHARS[(block shr 24) and 0x0F]) - ++i - ++j - } - if (j % blockCount == 0) { - f(s) - i = 0 - } - } - if (extraBytes != 0) { - val block = s[i] - hex.append(HEX_CHARS[(block shr 4) and 0x0F]) - hex.append(HEX_CHARS[block and 0x0F]) - if (extraBytes > 1) { - hex.append(HEX_CHARS[(block shr 12) and 0x0F]) - hex.append(HEX_CHARS[(block shr 8) and 0x0F]) - } - if (extraBytes > 2) { - hex.append(HEX_CHARS[(block shr 20) and 0x0F]) - hex.append(HEX_CHARS[(block shr 16) and 0x0F]) - } - } - return hex.toString() - } - - fun arrayBuffer(): UByteArray { - this.finalize() - - val blockCount = this.blockCount - val s = this.s - val outputBlocks = this.outputBlocks - val extraBytes = this.extraBytes - var i = 0 - var j = 0 - val bytes = this.outputBits shr 3 - val array: UIntArray = when { - extraBytes != 0 -> UIntArray((outputBlocks + 1)) - else -> UIntArray(bytes / 4) - } - while (j < outputBlocks) { - i = 0 - while (i < blockCount && j < outputBlocks) { - array[j] = s[i].toUInt() - ++i - ++j - } - if (j % blockCount == 0) { - f(s) - } - } - if (extraBytes != 0) { - array[i] = s[i].toUInt() - buffer = buffer.copyOfRange(0, bytes) - } - return buffer - } - - fun digest(): UByteArray { - this.finalize() - - val blockCount = this.blockCount - val s = this.s - val outputBlocks = this.outputBlocks - val extraBytes = this.extraBytes - var i = 0 - var j = 0 - val array = UByteArray(outputBlocks * 4) - var offset: Int - var block: Int - while (j < outputBlocks) { - i = 0 - while (i < blockCount && j < outputBlocks) { - offset = j shl 2 - block = s[i] - array[offset + 0] = ((block shr 0) and 0xFF).toUByte() - array[offset + 1] = ((block shr 8) and 0xFF).toUByte() - array[offset + 2] = ((block shr 16) and 0xFF).toUByte() - array[offset + 3] = ((block shr 24) and 0xFF).toUByte() - ++i - ++j - } - if (j % blockCount == 0) { - f(s) - } - } - if (extraBytes != 0) { - offset = j shl 2 - block = s[i] - array[offset] = (block and 0xFF).toUByte() - if (extraBytes > 1) { - array[offset + 1] = ((block shr 8) and 0xFF).toUByte() - } - if (extraBytes > 2) { - array[offset + 2] = ((block shr 16) and 0xFF).toUByte() - } - } - return array - } - - } - - class Kmac(bits: Int, padding: IntArray, outputBits: Int) : Keccak(bits, padding, outputBits) { - override fun finalize() { - this.encode(this.outputBits, true) - return super.finalize() - } - } - - fun f(s: IntArray) { - for (n in 0 until 48 step 2) { - val c0 = s[0] xor s[10] xor s[20] xor s[30] xor s[40] - val c1 = s[1] xor s[11] xor s[21] xor s[31] xor s[41] - val c2 = s[2] xor s[12] xor s[22] xor s[32] xor s[42] - val c3 = s[3] xor s[13] xor s[23] xor s[33] xor s[43] - val c4 = s[4] xor s[14] xor s[24] xor s[34] xor s[44] - val c5 = s[5] xor s[15] xor s[25] xor s[35] xor s[45] - val c6 = s[6] xor s[16] xor s[26] xor s[36] xor s[46] - val c7 = s[7] xor s[17] xor s[27] xor s[37] xor s[47] - val c8 = s[8] xor s[18] xor s[28] xor s[38] xor s[48] - val c9 = s[9] xor s[19] xor s[29] xor s[39] xor s[49] - - var h = c8 xor ((c2 shl 1) or (c3 ushr 31)) - var l = c9 xor ((c3 shl 1) or (c2 ushr 31)) - s[0] = s[0] xor h - s[1] = s[1] xor l - s[10] = s[10] xor h - s[11] = s[11] xor l - s[20] = s[20] xor h - s[21] = s[21] xor l - s[30] = s[30] xor h - s[31] = s[31] xor l - s[40] = s[40] xor h - s[41] = s[41] xor l - h = c0 xor ((c4 shl 1) or (c5 ushr 31)) - l = c1 xor ((c5 shl 1) or (c4 ushr 31)) - s[2] = s[2] xor h - s[3] = s[3] xor l - s[12] = s[12] xor h - s[13] = s[13] xor l - s[22] = s[22] xor h - s[23] = s[23] xor l - s[32] = s[32] xor h - s[33] = s[33] xor l - s[42] = s[42] xor h - s[43] = s[43] xor l - h = c2 xor ((c6 shl 1) or (c7 ushr 31)) - l = c3 xor ((c7 shl 1) or (c6 ushr 31)) - s[4] = s[4] xor h - s[5] = s[5] xor l - s[14] = s[14] xor h - s[15] = s[15] xor l - s[24] = s[24] xor h - s[25] = s[25] xor l - s[34] = s[34] xor h - s[35] = s[35] xor l - s[44] = s[44] xor h - s[45] = s[45] xor l - h = c4 xor ((c8 shl 1) or (c9 ushr 31)) - l = c5 xor ((c9 shl 1) or (c8 ushr 31)) - s[6] = s[6] xor h - s[7] = s[7] xor l - s[16] = s[16] xor h - s[17] = s[17] xor l - s[26] = s[26] xor h - s[27] = s[27] xor l - s[36] = s[36] xor h - s[37] = s[37] xor l - s[46] = s[46] xor h - s[47] = s[47] xor l - h = c6 xor ((c0 shl 1) or (c1 ushr 31)) - l = c7 xor ((c1 shl 1) or (c0 ushr 31)) - s[8] = s[8] xor h - s[9] = s[9] xor l - s[18] = s[18] xor h - s[19] = s[19] xor l - s[28] = s[28] xor h - s[29] = s[29] xor l - s[38] = s[38] xor h - s[39] = s[39] xor l - s[48] = s[48] xor h - s[49] = s[49] xor l - - val b00 = s[0] - val b01 = s[1] - val b32 = (s[11] shl 4) or (s[10] ushr 28) - val b33 = (s[10] shl 4) or (s[11] ushr 28) - val b14 = (s[20] shl 3) or (s[21] ushr 29) - val b15 = (s[21] shl 3) or (s[20] ushr 29) - val b46 = (s[31] shl 9) or (s[30] ushr 23) - val b47 = (s[30] shl 9) or (s[31] ushr 23) - val b28 = (s[40] shl 18) or (s[41] ushr 14) - val b29 = (s[41] shl 18) or (s[40] ushr 14) - val b20 = (s[2] shl 1) or (s[3] ushr 31) - val b21 = (s[3] shl 1) or (s[2] ushr 31) - val b02 = (s[13] shl 12) or (s[12] ushr 20) - val b03 = (s[12] shl 12) or (s[13] ushr 20) - val b34 = (s[22] shl 10) or (s[23] ushr 22) - val b35 = (s[23] shl 10) or (s[22] ushr 22) - val b16 = (s[33] shl 13) or (s[32] ushr 19) - val b17 = (s[32] shl 13) or (s[33] ushr 19) - val b48 = (s[42] shl 2) or (s[43] ushr 30) - val b49 = (s[43] shl 2) or (s[42] ushr 30) - val b40 = (s[5] shl 30) or (s[4] ushr 2) - val b41 = (s[4] shl 30) or (s[5] ushr 2) - val b22 = (s[14] shl 6) or (s[15] ushr 26) - val b23 = (s[15] shl 6) or (s[14] ushr 26) - val b04 = (s[25] shl 11) or (s[24] ushr 21) - val b05 = (s[24] shl 11) or (s[25] ushr 21) - val b36 = (s[34] shl 15) or (s[35] ushr 17) - val b37 = (s[35] shl 15) or (s[34] ushr 17) - val b18 = (s[45] shl 29) or (s[44] ushr 3) - val b19 = (s[44] shl 29) or (s[45] ushr 3) - val b10 = (s[6] shl 28) or (s[7] ushr 4) - val b11 = (s[7] shl 28) or (s[6] ushr 4) - val b42 = (s[17] shl 23) or (s[16] ushr 9) - val b43 = (s[16] shl 23) or (s[17] ushr 9) - val b24 = (s[26] shl 25) or (s[27] ushr 7) - val b25 = (s[27] shl 25) or (s[26] ushr 7) - val b06 = (s[36] shl 21) or (s[37] ushr 11) - val b07 = (s[37] shl 21) or (s[36] ushr 11) - val b38 = (s[47] shl 24) or (s[46] ushr 8) - val b39 = (s[46] shl 24) or (s[47] ushr 8) - val b30 = (s[8] shl 27) or (s[9] ushr 5) - val b31 = (s[9] shl 27) or (s[8] ushr 5) - val b12 = (s[18] shl 20) or (s[19] ushr 12) - val b13 = (s[19] shl 20) or (s[18] ushr 12) - val b44 = (s[29] shl 7) or (s[28] ushr 25) - val b45 = (s[28] shl 7) or (s[29] ushr 25) - val b26 = (s[38] shl 8) or (s[39] ushr 24) - val b27 = (s[39] shl 8) or (s[38] ushr 24) - val b08 = (s[48] shl 14) or (s[49] ushr 18) - val b09 = (s[49] shl 14) or (s[48] ushr 18) - - s[0] = b00 xor (b02.inv() and b04) - s[1] = b01 xor (b03.inv() and b05) - s[10] = b10 xor (b12.inv() and b14) - s[11] = b11 xor (b13.inv() and b15) - s[20] = b20 xor (b22.inv() and b24) - s[21] = b21 xor (b23.inv() and b25) - s[30] = b30 xor (b32.inv() and b34) - s[31] = b31 xor (b33.inv() and b35) - s[40] = b40 xor (b42.inv() and b44) - s[41] = b41 xor (b43.inv() and b45) - s[2] = b02 xor (b04.inv() and b06) - s[3] = b03 xor (b05.inv() and b07) - s[12] = b12 xor (b14.inv() and b16) - s[13] = b13 xor (b15.inv() and b17) - s[22] = b22 xor (b24.inv() and b26) - s[23] = b23 xor (b25.inv() and b27) - s[32] = b32 xor (b34.inv() and b36) - s[33] = b33 xor (b35.inv() and b37) - s[42] = b42 xor (b44.inv() and b46) - s[43] = b43 xor (b45.inv() and b47) - s[4] = b04 xor (b06.inv() and b08) - s[5] = b05 xor (b07.inv() and b09) - s[14] = b14 xor (b16.inv() and b18) - s[15] = b15 xor (b17.inv() and b19) - s[24] = b24 xor (b26.inv() and b28) - s[25] = b25 xor (b27.inv() and b29) - s[34] = b34 xor (b36.inv() and b38) - s[35] = b35 xor (b37.inv() and b39) - s[44] = b44 xor (b46.inv() and b48) - s[45] = b45 xor (b47.inv() and b49) - s[6] = b06 xor (b08.inv() and b00) - s[7] = b07 xor (b09.inv() and b01) - s[16] = b16 xor (b18.inv() and b10) - s[17] = b17 xor (b19.inv() and b11) - s[26] = b26 xor (b28.inv() and b20) - s[27] = b27 xor (b29.inv() and b21) - s[36] = b36 xor (b38.inv() and b30) - s[37] = b37 xor (b39.inv() and b31) - s[46] = b46 xor (b48.inv() and b40) - s[47] = b47 xor (b49.inv() and b41) - s[8] = b08 xor (b00.inv() and b02) - s[9] = b09 xor (b01.inv() and b03) - s[18] = b18 xor (b10.inv() and b12) - s[19] = b19 xor (b11.inv() and b13) - s[28] = b28 xor (b20.inv() and b22) - s[29] = b29 xor (b21.inv() and b23) - s[38] = b38 xor (b30.inv() and b32) - s[39] = b39 xor (b31.inv() and b33) - s[48] = b48 xor (b40.inv() and b42) - s[49] = b49 xor (b41.inv() and b43) - - s[0] = s[0] xor RC[n].toInt() - s[1] = s[1] xor RC[n + 1].toInt() - } - } -} -4 krypto/src/commonMain/kotlin/korlibs/crypto/annotations/KryptoExperimental.kt -Viewed -@@ -0,0 +1,4 @@ -package korlibs.crypto.annotations - -@RequiresOptIn -annotation class KryptoExperimental -34 krypto/src/commonTest/kotlin/korlibs/crypto/SHA3Test.kt -Viewed -@@ -0,0 +1,34 @@ -package korlibs.crypto - -import korlibs.crypto.annotations.KryptoExperimental -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(KryptoExperimental::class) -class SHA3Test { - @Test - fun test() { - val sha3 = SHA3_256() - assertEquals("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", sha3.update(byteArrayOf()).digest().hexLower) - } -} - -/* -SHA3-224("") -6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7 -SHA3-256("") -a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a -SHA3-384("") -0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004 -SHA3-512("") -a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26 -SHAKE128("", 256) -7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26 -SHAKE256("", 512) -46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be -SHAKE128("The quick brown fox jumps over the lazy dog", 256) -f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e -SHAKE128("The quick brown fox jumps over the lazy dof", 256) -853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c - */ - - */ diff --git a/korge-foundation/src/korlibs/crypto/SHA512.kt b/korge-foundation/src/korlibs/crypto/SHA512.kt deleted file mode 100644 index 310743d640..0000000000 --- a/korge-foundation/src/korlibs/crypto/SHA512.kt +++ /dev/null @@ -1,200 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* - -// https://git.suckless.org/sbase/file/libutil/sha512.c.html -// https://git.suckless.org/sbase/file/sha512.h.html -/* public domain sha512 implementation based on fips180-3 */ -@OptIn(ExperimentalUnsignedTypes::class) -class SHA512 : SHA(chunkSize = 128, digestSize = 64) { - companion object : HasherFactory("SHA512", { SHA512() }) { - private const val SHA512_DIGEST_LENGTH = 64 - - private fun ror(n: ULong, k: Int): ULong = (n shr k) or (n shl (64 - k)) - private fun Ch(x: ULong, y: ULong, z: ULong) = (z xor (x and (y xor z))) - private fun Maj(x: ULong, y: ULong, z: ULong) = ((x and y) or (z and (x or y))) - private fun S0(x: ULong) = (ror(x, 28) xor ror(x, 34) xor ror(x, 39)) - private fun S1(x: ULong) = (ror(x, 14) xor ror(x, 18) xor ror(x, 41)) - private fun R0(x: ULong) = (ror(x, 1) xor ror(x, 8) xor (x shr 7)) - private fun R1(x: ULong) = (ror(x, 19) xor ror(x, 61) xor (x shr 6)) - - private val K = ulongArrayOf( - 0x428a2f98d728ae22uL, 0x7137449123ef65cduL, 0xb5c0fbcfec4d3b2fuL, 0xe9b5dba58189dbbcuL, - 0x3956c25bf348b538uL, 0x59f111f1b605d019uL, 0x923f82a4af194f9buL, 0xab1c5ed5da6d8118uL, - 0xd807aa98a3030242uL, 0x12835b0145706fbeuL, 0x243185be4ee4b28cuL, 0x550c7dc3d5ffb4e2uL, - 0x72be5d74f27b896fuL, 0x80deb1fe3b1696b1uL, 0x9bdc06a725c71235uL, 0xc19bf174cf692694uL, - 0xe49b69c19ef14ad2uL, 0xefbe4786384f25e3uL, 0x0fc19dc68b8cd5b5uL, 0x240ca1cc77ac9c65uL, - 0x2de92c6f592b0275uL, 0x4a7484aa6ea6e483uL, 0x5cb0a9dcbd41fbd4uL, 0x76f988da831153b5uL, - 0x983e5152ee66dfabuL, 0xa831c66d2db43210uL, 0xb00327c898fb213fuL, 0xbf597fc7beef0ee4uL, - 0xc6e00bf33da88fc2uL, 0xd5a79147930aa725uL, 0x06ca6351e003826fuL, 0x142929670a0e6e70uL, - 0x27b70a8546d22ffcuL, 0x2e1b21385c26c926uL, 0x4d2c6dfc5ac42aeduL, 0x53380d139d95b3dfuL, - 0x650a73548baf63deuL, 0x766a0abb3c77b2a8uL, 0x81c2c92e47edaee6uL, 0x92722c851482353buL, - 0xa2bfe8a14cf10364uL, 0xa81a664bbc423001uL, 0xc24b8b70d0f89791uL, 0xc76c51a30654be30uL, - 0xd192e819d6ef5218uL, 0xd69906245565a910uL, 0xf40e35855771202auL, 0x106aa07032bbd1b8uL, - 0x19a4c116b8d2d0c8uL, 0x1e376c085141ab53uL, 0x2748774cdf8eeb99uL, 0x34b0bcb5e19b48a8uL, - 0x391c0cb3c5c95a63uL, 0x4ed8aa4ae3418acbuL, 0x5b9cca4f7763e373uL, 0x682e6ff3d6b2b8a3uL, - 0x748f82ee5defb2fcuL, 0x78a5636f43172f60uL, 0x84c87814a1f0ab72uL, 0x8cc702081a6439ecuL, - 0x90befffa23631e28uL, 0xa4506cebde82bde9uL, 0xbef9a3f7b2c67915uL, 0xc67178f2e372532buL, - 0xca273eceea26619cuL, 0xd186b8c721c0c207uL, 0xeada7dd6cde0eb1euL, 0xf57d4f7fee6ed178uL, - 0x06f067aa72176fbauL, 0x0a637dc5a2c898a6uL, 0x113f9804bef90daeuL, 0x1b710b35131c471buL, - 0x28db77f523047d84uL, 0x32caab7b40c72493uL, 0x3c9ebe0a15c9bebcuL, 0x431d67c49c100d4cuL, - 0x4cc5d4becb3e42b6uL, 0x597f299cfc657e2auL, 0x5fcb6fab3ad6faecuL, 0x6c44198c4a475817uL - ) - } - - var len = 0uL - val h = ULongArray(8) - val buf = UByteArray(128) - - init { - coreReset() - } - - override fun coreReset() { - len = 0uL - h[0] = 0x6a09e667f3bcc908uL - h[1] = 0xbb67ae8584caa73buL - h[2] = 0x3c6ef372fe94f82buL - h[3] = 0xa54ff53a5f1d36f1uL - h[4] = 0x510e527fade682d1uL - h[5] = 0x9b05688c2b3e6c1fuL - h[6] = 0x1f83d9abfb41bd6buL - h[7] = 0x5be0cd19137e2179uL - buf.fill(0u) - } - - // @TODO: The super update doesn't work with SHA512, do we have to fix something? - override fun update(data: ByteArray, offset: Int, count: Int): Hasher { - sha512_update(data.asUByteArray(), offset, count) - totalWritten += count - return this - } - - override fun digestOut(out: ByteArray) { - sha512_sum(out.asUByteArray()) - reset() - } - - override fun coreUpdate(chunk: ByteArray) { - sha512_update(chunk.asUByteArray(), 0, chunk.size) - } - - override fun coreDigest(out: ByteArray) { - sha512_sum(out.asUByteArray()) - } - - private val W = ULongArray(80) - - private fun processblock(buf: UByteArray, p: Int = 0) { - for (i in 0 until 16) { - var v = 0uL - v = v or (buf[p + 8 * i + 0].toULong() shl 56) - v = v or (buf[p + 8 * i + 1].toULong() shl 48) - v = v or (buf[p + 8 * i + 2].toULong() shl 40) - v = v or (buf[p + 8 * i + 3].toULong() shl 32) - v = v or (buf[p + 8 * i + 4].toULong() shl 24) - v = v or (buf[p + 8 * i + 5].toULong() shl 16) - v = v or (buf[p + 8 * i + 6].toULong() shl 8) - v = v or (buf[p + 8 * i + 7].toULong() shl 0) - W[i] = v - } - for (i in 16 until 80) { - W[i] = R1(W[i - 2]) + W[i - 7] + R0(W[i - 15]) + W[i - 16] - } - var a = this.h[0] - var b = this.h[1] - var c = this.h[2] - var d = this.h[3] - var e = this.h[4] - var f = this.h[5] - var g = this.h[6] - var h = this.h[7] - for (i in 0 until 80) { - val t1 = h + S1(e) + Ch(e, f, g) + K[i] + W[i] - val t2 = S0(a) + Maj(a, b, c) - h = g - g = f - f = e - e = d + t1 - d = c - c = b - b = a - a = t1 + t2 - } - this.h[0] += a - this.h[1] += b - this.h[2] += c - this.h[3] += d - this.h[4] += e - this.h[5] += f - this.h[6] += g - this.h[7] += h - } - - private fun pad() { - var r = (this.len % 128uL).toInt() - - this.buf[r++] = 0x80u - if (r > 112) { - this.buf.fill(0u, r, 128) - r = 0 - processblock(buf) - } - this.buf.fill(0u, r, 120) - this.len *= 8uL - this.buf[120] = (this.len shr 56).toUByte() - this.buf[121] = (this.len shr 48).toUByte() - this.buf[122] = (this.len shr 40).toUByte() - this.buf[123] = (this.len shr 32).toUByte() - this.buf[124] = (this.len shr 24).toUByte() - this.buf[125] = (this.len shr 16).toUByte() - this.buf[126] = (this.len shr 8).toUByte() - this.buf[127] = (this.len shr 0).toUByte() - processblock(this.buf) - } - - private fun sha512_sum(md: UByteArray) { - sha512_sum_n(md, 8) - } - - private fun sha512_sum_n(md: UByteArray, n: Int) { - pad() - for (i in 0 until n) { - md[8 * i + 0] = (h[i] shr 56).toUByte() - md[8 * i + 1] = (h[i] shr 48).toUByte() - md[8 * i + 2] = (h[i] shr 40).toUByte() - md[8 * i + 3] = (h[i] shr 32).toUByte() - md[8 * i + 4] = (h[i] shr 24).toUByte() - md[8 * i + 5] = (h[i] shr 16).toUByte() - md[8 * i + 6] = (h[i] shr 8).toUByte() - md[8 * i + 7] = (h[i] shr 0).toUByte() - } - } - - private fun sha512_update(m: UByteArray, p: Int, len: Int) { - var len = len - var p = p - val r = (this.len % 128uL).toInt() - - this.len += len.toULong() - if (r != 0) { - if (len < 128 - r) { - arraycopy(m.asByteArray(), p, this.buf.asByteArray(), r, len) - return - } - arraycopy(m.asByteArray(), p, buf.asByteArray(), r, 128 - r) - len -= 128 - r - p += 128 - r - processblock(this.buf) - } - while (len >= 128) { - processblock(m, p) - len -= 128 - p += 128 - } - arraycopy(m.asByteArray(), p, buf.asByteArray(), 0, len) - } - -} - -fun ByteArray.sha512() = hash(SHA512) diff --git a/korge-foundation/src/korlibs/crypto/SecureRandom.kt b/korge-foundation/src/korlibs/crypto/SecureRandom.kt deleted file mode 100644 index 5b6e0b0ec9..0000000000 --- a/korge-foundation/src/korlibs/crypto/SecureRandom.kt +++ /dev/null @@ -1,41 +0,0 @@ -package korlibs.crypto - -import korlibs.memory.* -import kotlin.random.Random - -expect fun fillRandomBytes(array: ByteArray) -expect fun seedExtraRandomBytes(array: ByteArray) - -internal fun seedExtraRandomBytesDefault(array: ByteArray) { - for (v in array) { - val count = v.toInt() and 0xFF - fillRandomBytes(ByteArray(count)) - } -} - -object SecureRandom : Random() { - fun addSeed(array: ByteArray) { - seedExtraRandomBytes(array) - } - - private fun getInt(): Int { - val temp = ByteArray(4) - fillRandomBytes(temp) - val a = temp[0].toInt() and 0xFF - val b = temp[1].toInt() and 0xFF - val c = temp[2].toInt() and 0xFF - val d = temp[3].toInt() and 0xFF - return (a shl 24) or (b shl 16) or (c shl 8) or (d shl 0) - } - - override fun nextBytes(array: ByteArray, fromIndex: Int, toIndex: Int): ByteArray { - val random = ByteArray(toIndex - fromIndex) - fillRandomBytes(random) - arraycopy(random, 0, array, fromIndex, random.size) - return array - } - - override fun nextBits(bitCount: Int): Int { - return getInt() and ((1 shl bitCount) - 1) - } -} diff --git a/korge-foundation/src@android/korlibs/crypto/PRNGFixes.kt b/korge-foundation/src@android/korlibs/crypto/PRNGFixes.kt deleted file mode 100644 index f1043308e9..0000000000 --- a/korge-foundation/src@android/korlibs/crypto/PRNGFixes.kt +++ /dev/null @@ -1,329 +0,0 @@ -package korlibs.crypto - -/* - * This software is provided 'as-is', without any express or implied - * warranty. In no event will Google be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, as long as the origin is not misrepresented. - */ - -import android.graphics.Bitmap -import android.os.Build -import android.os.Process -import android.util.Log -import java.io.* -import java.security.NoSuchAlgorithmException -import java.security.Provider -import java.security.SecureRandom -import java.security.SecureRandomSpi -import java.security.Security - -/** - * Fixes for the output of the default PRNG having low entropy. - * - * The fixes need to be applied via [.apply] before any use of Java - * Cryptography Architecture primitives. A good place to invoke them is in the - * application's `onCreate`. - */ -object PRNGFixes { - - private const val VERSION_CODE_JELLY_BEAN = 16 - private const val VERSION_CODE_JELLY_BEAN_MR2 = 18 - private val BUILD_FINGERPRINT_AND_DEVICE_SERIAL: ByteArray = run { - val result = StringBuilder() - val fingerprint = Build.FINGERPRINT - if (fingerprint != null) { - result.append(fingerprint) - } - val serial = deviceSerialNumber - if (serial != null) { - result.append(serial) - } - try { - result.toString().toByteArray(charset("UTF-8")) - } catch (e: UnsupportedEncodingException) { - throw RuntimeException("UTF-8 encoding not supported") - } - } - - /** - * Gets the hardware serial number of this device. - * - * @return serial number or `null` if not available. - */ - private// We're using the Reflection API because Build.SERIAL is only available - // since API Level 9 (Gingerbread, Android 2.3). - val deviceSerialNumber: String? - get() = try { - Build::class.java.getField("SERIAL").get(null) as String - } catch (ignored: Exception) { - null - } - - /** - * Applies all fixes. - * - * @throws SecurityException if a fix is needed but could not be applied. - */ - fun apply() { - val notMockedUnittests = kotlin.runCatching { Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) }.isSuccess - if (notMockedUnittests) { - applyOpenSSLFix() - installLinuxPRNGSecureRandom() - } - } - - /** - * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the - * fix is not needed. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - @Throws(SecurityException::class) - private fun applyOpenSSLFix() { - if (Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN || Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) { - // No need to apply the fix - return - } - - try { - // Mix in the device- and invocation-specific seed. - Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_seed", ByteArray::class.java) - .invoke(null, generateSeed()) - - // Mix output of Linux PRNG into OpenSSL's PRNG - val bytesRead = Class.forName( - "org.apache.harmony.xnet.provider.jsse.NativeCrypto" - ) - .getMethod("RAND_load_file", String::class.java, Long::class.javaPrimitiveType) - .invoke(null, "/dev/urandom", 1024) as Int - if (bytesRead != 1024) { - throw IOException( - "Unexpected number of bytes read from Linux PRNG: $bytesRead" - ) - } - } catch (e: Exception) { - throw SecurityException("Failed to seed OpenSSL PRNG", e) - } - - } - - /** - * Installs a Linux PRNG-backed `SecureRandom` implementation as the - * default. Does nothing if the implementation is already the default or if - * there is not need to install the implementation. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - @Throws(SecurityException::class) - private fun installLinuxPRNGSecureRandom() { - if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) { - // No need to apply the fix - return - } - - // Install a Linux PRNG-based SecureRandom implementation as the - // default, if not yet installed. - val secureRandomProviders = Security.getProviders("SecureRandom.SHA1PRNG") - if (secureRandomProviders == null - || secureRandomProviders.isEmpty() - || LinuxPRNGSecureRandomProvider::class.java != secureRandomProviders[0].javaClass - ) { - Security.insertProviderAt(LinuxPRNGSecureRandomProvider(), 1) - } - - // Assert that new SecureRandom() and - // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed - // by the Linux PRNG-based SecureRandom implementation. - val rng1 = SecureRandom() - if (LinuxPRNGSecureRandomProvider::class.java != rng1.provider.javaClass) { - throw SecurityException( - "new SecureRandom() backed by wrong Provider: " + rng1.provider.javaClass - ) - } - - val rng2: SecureRandom - try { - rng2 = SecureRandom.getInstance("SHA1PRNG") - } catch (e: NoSuchAlgorithmException) { - throw SecurityException("SHA1PRNG not available", e) - } - - if (LinuxPRNGSecureRandomProvider::class.java != rng2.provider.javaClass) { - throw SecurityException( - "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" - + " Provider: " + rng2.provider.javaClass - ) - } - } - - /** - * `Provider` of `SecureRandom` engines which pass through - * all requests to the Linux PRNG. - */ - private class LinuxPRNGSecureRandomProvider : - Provider("LinuxPRNG", 1.0, ("A Linux-specific random number provider that uses" + " /dev/urandom")) { - init { - // Although /dev/urandom is not a SHA-1 PRNG, some apps - // explicitly request a SHA1PRNG SecureRandom and we thus need to - // prevent them from getting the default implementation whose output - // may have low entropy. - put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom::class.java.name) - put("SecureRandom.SHA1PRNG ImplementedIn", "Software") - } - } - - /** - * [SecureRandomSpi] which passes all requests to the Linux PRNG - * (`/dev/urandom`). - */ - class LinuxPRNGSecureRandom : SecureRandomSpi() { - - /** - * Whether this engine instance has been seeded. This is needed because - * each instance needs to seed itself if the client does not explicitly - * seed it. - */ - private var mSeeded: Boolean = false - - private// NOTE: Consider inserting a BufferedInputStream between - // DataInputStream and FileInputStream if you need higher - // PRNG output performance and can live with future PRNG - // output being pulled into this process prematurely. - val urandomInputStream: DataInputStream - get() = synchronized(sLock) { - if (sUrandomIn == null) { - try { - sUrandomIn = DataInputStream( - FileInputStream(URANDOM_FILE) - ) - } catch (e: IOException) { - throw SecurityException( - ("Failed to open " - + URANDOM_FILE + " for reading"), e - ) - } - - } - return sUrandomIn!! - } - - private val urandomOutputStream: OutputStream - @Throws(IOException::class) - get() = synchronized(sLock) { - if (sUrandomOut == null) { - sUrandomOut = FileOutputStream(URANDOM_FILE) - } - return sUrandomOut!! - } - - override fun engineSetSeed(bytes: ByteArray) { - try { - val out: OutputStream - synchronized(sLock) { - out = urandomOutputStream - } - out.write(bytes) - out.flush() - } catch (e: IOException) { - // On a small fraction of devices /dev/urandom is not writable. - // Log and ignore. - Log.w( - PRNGFixes::class.java.simpleName, - "Failed to mix seed into $URANDOM_FILE" - ) - } finally { - mSeeded = true - } - } - - override fun engineNextBytes(bytes: ByteArray) { - if (!mSeeded) { - // Mix in the device- and invocation-specific seed. - engineSetSeed(generateSeed()) - } - - try { - val `in`: DataInputStream - synchronized(sLock) { - `in` = urandomInputStream - } - synchronized(`in`) { - `in`.readFully(bytes) - } - } catch (e: IOException) { - throw SecurityException( - "Failed to read from $URANDOM_FILE", e - ) - } - - } - - override fun engineGenerateSeed(size: Int): ByteArray { - val seed = ByteArray(size) - engineNextBytes(seed) - return seed - } - - companion object { - - /* - * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed - * are passed through to the Linux PRNG (/dev/urandom). Instances of - * this class seed themselves by mixing in the current time, PID, UID, - * build fingerprint, and hardware serial number (where available) into - * Linux PRNG. - * - * Concurrency: Read requests to the underlying Linux PRNG are - * serialized (on sLock) to ensure that multiple threads do not get - * duplicated PRNG output. - */ - - private val URANDOM_FILE = File("/dev/urandom") - - private val sLock = Any() - - /** - * Input stream for reading from Linux PRNG or `null` if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private var sUrandomIn: DataInputStream? = null - - /** - * Output stream for writing to Linux PRNG or `null` if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private var sUrandomOut: OutputStream? = null - } - } - - /** - * Generates a device- and invocation-specific seed to be mixed into the - * Linux PRNG. - */ - private fun generateSeed(): ByteArray { - try { - val seedBuffer = ByteArrayOutputStream() - val seedBufferOut = DataOutputStream(seedBuffer) - seedBufferOut.writeLong(System.currentTimeMillis()) - seedBufferOut.writeLong(System.nanoTime()) - seedBufferOut.writeInt(Process.myPid()) - seedBufferOut.writeInt(Process.myUid()) - seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL) - seedBufferOut.close() - return seedBuffer.toByteArray() - } catch (e: IOException) { - throw SecurityException("Failed to generate seed", e) - } - - } -} -/** Hidden constructor to prevent instantiation. */ diff --git a/korge-foundation/src@android/korlibs/crypto/SecureRandomJvm.kt b/korge-foundation/src@android/korlibs/crypto/SecureRandomJvm.kt deleted file mode 100644 index c68aacce66..0000000000 --- a/korge-foundation/src@android/korlibs/crypto/SecureRandomJvm.kt +++ /dev/null @@ -1,16 +0,0 @@ -package korlibs.crypto - -import java.security.SecureRandom - -private val jrandom by lazy { - PRNGFixes.apply() - SecureRandom() -} - -actual fun fillRandomBytes(array: ByteArray) { - jrandom.nextBytes(array) -} - -actual fun seedExtraRandomBytes(array: ByteArray) { - jrandom.setSeed(array) -} diff --git a/korge-foundation/src@darwin/korlibs/crypto/SecureRandomNativePosix.kt b/korge-foundation/src@darwin/korlibs/crypto/SecureRandomNativePosix.kt deleted file mode 100644 index ea0bcbbd92..0000000000 --- a/korge-foundation/src@darwin/korlibs/crypto/SecureRandomNativePosix.kt +++ /dev/null @@ -1,36 +0,0 @@ -package korlibs.crypto - -import kotlinx.cinterop.* -import platform.Security.* -import platform.posix.* - -// https://developer.apple.com/documentation/security/randomization_services -actual fun fillRandomBytes(array: ByteArray) { - if (array.isEmpty()) return - - array.usePinned { pin -> - val ptr = pin.addressOf(0) - val status = SecRandomCopyBytes(kSecRandomDefault, array.size.convert(), ptr) - if (status != errSecSuccess) { - error("Error filling random bytes. errorCode=$status") - } - } -} - -actual fun seedExtraRandomBytes(array: ByteArray) { - if (array.isEmpty()) return - - try { - array.usePinned { pin -> - val ptr = pin.addressOf(0) - val file = fopen("/dev/urandom", "wb") - if (file != null) { - fwrite(ptr, 1.convert(), array.size.convert(), file) - for (n in 0 until array.size) array[n] = ptr[n] - fclose(file) - } - } - } catch (e: Throwable) { - e.printStackTrace() - } -} diff --git a/korge-foundation/src@js/korlibs/crypto/SecureRandomJs.kt b/korge-foundation/src@js/korlibs/crypto/SecureRandomJs.kt deleted file mode 100644 index 58a684c6ea..0000000000 --- a/korge-foundation/src@js/korlibs/crypto/SecureRandomJs.kt +++ /dev/null @@ -1,29 +0,0 @@ -package korlibs.crypto - -import org.khronos.webgl.Int8Array -import org.khronos.webgl.Uint8Array - -private val isNodeJs by lazy { js("(typeof process === 'object' && typeof require === 'function')").unsafeCast() } -//private external val require: dynamic -//private val require_req: dynamic by lazy { require } -//private fun require_node(name: String): dynamic = require_req(name) -private val _global: dynamic = js("((typeof global !== 'undefined') ? global : self)") - -// DIRTY HACK to prevent webpack to mess with our code -val REQ get() = "req" -private external val eval: dynamic -private fun require_node(name: String): dynamic = eval("(${REQ}uire('$name'))") - -actual fun fillRandomBytes(array: ByteArray) { - if (isNodeJs) { - // https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size - require_node("crypto").randomFillSync(Uint8Array(array.unsafeCast().buffer)) - } else { - // https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues - _global.crypto.getRandomValues(array) - } -} - -actual fun seedExtraRandomBytes(array: ByteArray) { - seedExtraRandomBytesDefault(array) -} diff --git a/korge-foundation/src@jvm/korlibs/crypto/SecureRandomJvm.kt b/korge-foundation/src@jvm/korlibs/crypto/SecureRandomJvm.kt deleted file mode 100644 index aeabca6b5e..0000000000 --- a/korge-foundation/src@jvm/korlibs/crypto/SecureRandomJvm.kt +++ /dev/null @@ -1,13 +0,0 @@ -package korlibs.crypto - -import java.security.SecureRandom - -private val jrandom = SecureRandom() - -actual fun fillRandomBytes(array: ByteArray) { - jrandom.nextBytes(array) -} - -actual fun seedExtraRandomBytes(array: ByteArray) { - jrandom.setSeed(array) -} diff --git a/korge-foundation/src@wasmJs/korlibs/crypto/SecureRandomNativeWasm.kt b/korge-foundation/src@wasmJs/korlibs/crypto/SecureRandomNativeWasm.kt deleted file mode 100644 index 2b52f03196..0000000000 --- a/korge-foundation/src@wasmJs/korlibs/crypto/SecureRandomNativeWasm.kt +++ /dev/null @@ -1,32 +0,0 @@ -package korlibs.crypto - -import org.khronos.webgl.* - -actual fun fillRandomBytes(array: ByteArray) { - val temp = Int8Array(array.size) - if (isNodeJs()) { - _fillRandomBytesNode(temp) - } else { - _fillRandomBytesBrowser(temp) - } - for (n in 0 until array.size) array[n] = temp[n] -} - -actual fun seedExtraRandomBytes(array: ByteArray) { - seedExtraRandomBytesDefault(array) -} - -@JsFun("() => { return (typeof process === 'object' && typeof require === 'function'); }") -private external fun isNodeJs(): Boolean - -@JsFun("""(array) => { - require_node("crypto").randomFillSync(Uint8Array(array.buffer)) -} -""") -private external fun _fillRandomBytesNode(array: Int8Array) - -@JsFun("""(array) => { - (globalThis || window || this).crypto.getRandomValues(array) -} -""") -private external fun _fillRandomBytesBrowser(array: Int8Array) diff --git a/korge-foundation/test/korlibs/crypto/AESTest.kt b/korge-foundation/test/korlibs/crypto/AESTest.kt deleted file mode 100644 index 9fde0b04eb..0000000000 --- a/korge-foundation/test/korlibs/crypto/AESTest.kt +++ /dev/null @@ -1,344 +0,0 @@ -package korlibs.crypto - -import korlibs.crypto.CipherPadding.Companion.NoPadding -import korlibs.encoding.* -import kotlin.random.Random -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - -class AESTest { - @Test - fun name() { - val plainText = Hex.decode("00112233445566778899aabbccddeeff") - val cipherKey = Hex.decode("000102030405060708090a0b0c0d0e0f") - val cipherText = Hex.decode("69c4e0d86a7b0430d8cdb78070b4c55a") - val iv = ByteArray(16) - assertEquals(plainText.toHexStringLower(), AES.decryptAesCbc(cipherText, cipherKey, iv, CipherPadding.NoPadding).toHexStringLower()) - assertEquals(cipherText.toHexStringLower(), AES.encryptAesCbc(plainText, cipherKey, iv, CipherPadding.NoPadding).toHexStringLower()) - } - - @Test - fun longName() { - val plainText = - Hex.decode("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff") - val cipherKey = Hex.decode("000102030405060708090a0b0c0d0e0f") - val iv = ByteArray(16) - val cipherText = AES.encryptAesCbc(plainText, cipherKey, iv, CipherPadding.NoPadding) - assertEquals(plainText.toHexStringLower(), AES.decryptAesCbc(cipherText, cipherKey, iv, CipherPadding.NoPadding).toHexStringLower()) - } - - @Test - fun aesModes() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - val modes = listOf( - CipherMode.ECB, - CipherMode.CBC, - CipherMode.PCBC, - CipherMode.CFB, - CipherMode.OFB, - CipherMode.CTR, - ) - for (mode in modes) { - for (i in 0..100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val iv = Random.nextBytes(16) - val padding = paddingValues[i % paddingValues.size] - val ivCopy = iv.copyOf() - - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val plainTextCopy = plainText.copyOf() - val cipher = AES(cipherKey)[mode, padding, iv] - val encryptedText = cipher.encrypt(plainText) - val encryptedTextCopy = encryptedText.copyOf() - val decryptedText = cipher.decrypt(encryptedText) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.hexLower, decryptedText.hexLower) - // Ensure we don't mutate input arrays - assertEquals(ivCopy.hexLower, iv.hexLower, "IV shouldn't be mutated") - assertEquals(plainTextCopy.hexLower, plainText.hexLower, "plainText shouldn't be mutated") - assertEquals(encryptedTextCopy.hexLower, encryptedText.hexLower, "encryptedText shouldn't be muated") - } - } - } - - @Test - fun aesEcb() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - for (i in 0..100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val padding = paddingValues[i % paddingValues.size] - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val encryptedText = AES.encryptAesEcb(plainText, cipherKey, padding) - val decryptedText = AES.decryptAesEcb(encryptedText, cipherKey, padding) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.toHexStringLower(), decryptedText.toHexStringLower()) - } - } - - @Test - fun aecCbc() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - for (i in 0..100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val iv = Random.nextBytes(16) - val padding = paddingValues[i % paddingValues.size] - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - //println("IV= " + iv.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val encryptedText = AES.encryptAesCbc(plainText, cipherKey, iv, padding) - val decryptedText = AES.decryptAesCbc(encryptedText, cipherKey, iv, padding) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.toHexStringLower(), decryptedText.toHexStringLower()) - } - } - - @Test - fun aecPcbc() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - for (i in 0..100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val iv = Random.nextBytes(16) - val padding = paddingValues[i % paddingValues.size] - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - //println("IV= " + iv.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val encryptedText = AES.encryptAesPcbc(plainText, cipherKey, iv, padding) - val decryptedText = AES.decryptAesPcbc(encryptedText, cipherKey, iv, padding) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.toHexStringLower(), decryptedText.toHexStringLower()) - } - } - - @Test - fun aecCtr() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - for (i in 0..100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val iv = Random.nextBytes(16) - val padding = paddingValues[i % paddingValues.size] - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - //println("IV= " + iv.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val encryptedText = AES.encryptAesCtr(plainText, cipherKey, iv, padding) - val decryptedText = AES.decryptAesCtr(encryptedText, cipherKey, iv, padding) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.toHexStringLower(), decryptedText.toHexStringLower()) - } - } - - @Test - fun aesCfb() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - for (i in 0 .. 100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val iv = Random.nextBytes(16) - val padding = paddingValues[i % paddingValues.size] - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - //println("IV= " + iv.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val encryptedText = AES.encryptAesCfb(plainText, cipherKey, iv, padding) - val decryptedText = AES.decryptAesCfb(encryptedText, cipherKey, iv, padding) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.toHexStringLower(), decryptedText.toHexStringLower()) - } - } - - @Test - fun aesOfb() { - val keySizeArray = intArrayOf(16, 24, 32) - val paddingValues = arrayListOf(Padding.NoPadding, Padding.PKCS7Padding, Padding.ANSIX923Padding, Padding.ISO10126Padding) - for (i in 0 .. 100) { - val keySize = keySizeArray[i % keySizeArray.size] - val cipherKey = Random.nextBytes(keySize) - val iv = Random.nextBytes(16) - val padding = paddingValues[i % paddingValues.size] - //println("KeySize=$keySize, Padding=$padding") - //println("Key= " + cipherKey.contentToString()) - //println("IV= " + iv.contentToString()) - val dataSize = if (padding == Padding.NoPadding) 16 else Random.nextInt(32) - val plainText = Random.nextBytes(dataSize) - val encryptedText = AES.encryptAesOfb(plainText, cipherKey, iv, padding) - val decryptedText = AES.decryptAesOfb(encryptedText, cipherKey, iv, padding) - //println("PlainText= ${plainText.contentToString()}") - //println("EncryptText= ${encryptedText.contentToString()}") - //println("DecryptText= ${decryptedText.contentToString()}") - //println() - assertEquals(plainText.toHexStringLower(), decryptedText.toHexStringLower()) - } - } - - // https://github.com/korlibs/krypto/discussions/44 - @Test - fun aesEncryptOutOfBounds() { - val iv = "000102030405060708090a0b0c0d0e0f".unhex - val data = "0000040100000000000e0000000e000104010100".unhex - val key = "11090c51a42c0b98cd2b7b7480d80dc86458258c010c306e60e94cde7f8eaffb".unhex - - AES.encryptAesCbc(data, key, iv, Padding.NoPadding) - // Data not aligned, and NoPadding used, it should fail - //assertFailsWith { AES.encryptAesCbc(data, key, iv, Padding.NoPadding) } - //assertFailsWith { AES.encryptAes128Cbc(data, key) } - assertEquals( - "6ed24a2790e3bb1a3cecd89c6d33b487cb2c38471ea7e3c2771ab537fb23875e", - AES.encryptAesCbc(data, key, iv, Padding.ZeroPadding).hex - ) - assertEquals( - "6ed24a2790e3bb1a3cecd89c6d33b487cb2c38471ea7e3c2771ab537fb23875e", - AES.encryptAesCbc(data, key, iv, padding = Padding.ZeroPadding).hex - ) - } - - @Test - fun test2() { - val key = ByteArray(32) { (it + 1).toByte() } - val nonce = ByteArray(8) { (it + 1).toByte() } - val initialisationVector = nonce + ByteArray(8) - assertEquals("14e2d5701d", AES.encryptAesCtr("hello".encodeToByteArray(), key, initialisationVector, Padding.NoPadding).hex) - assertEquals("hello", AES.decryptAesCtr("14e2d5701d".unhex, key, initialisationVector, Padding.NoPadding).decodeToString()) - } - - @Test - fun testAESShouldFail() { - val exception = assertFailsWith { - val anyData = Random.Default.nextBytes(ByteArray(1)) - val anyKey = Random.Default.nextBytes(ByteArray(128 / 8)) - val invalidIV = ByteArray(15) // This should be at least 16 bytes long - AES.decryptAesCtr( - data = anyData, - key = anyKey, - iv = invalidIV, - padding = NoPadding - ) - } - assertEquals("Wrong IV length: must be 16 bytes long", exception.message) - } -} - -/* -http://www.herongyang.com/Cryptography/AES-Example-Vector-of-AES-Encryption.html - -Plaintext: 00112233445566778899aabbccddeeff -Cipher key: 000102030405060708090a0b0c0d0e0f -Ciphertext: 69c4e0d86a7b0430d8cdb78070b4c55a - -Encryption rounds, round keys and state values: - -Round 0: - state: 00112233445566778899aabbccddeeff <-- Plaintext - round key: 000102030405060708090a0b0c0d0e0f - state: 00102030405060708090a0b0c0d0e0f0 <-- AddRoundKey() - -Round 1: - state: 63cab7040953d051cd60e0e7ba70e18c <-- SubBytes() - state: 6353e08c0960e104cd70b751bacad0e7 <-- ShiftRows() - state: 5f72641557f5bc92f7be3b291db9f91a <-- MixColumns() - round key: d6aa74fdd2af72fadaa678f1d6ab76fe - state: 89d810e8855ace682d1843d8cb128fe4 <-- AddRoundKey() - -Round 2: - state: a761ca9b97be8b45d8ad1a611fc97369 <-- SubBytes() - state: a7be1a6997ad739bd8c9ca451f618b61 <-- ShiftRows() - state: ff87968431d86a51645151fa773ad009 <-- MixColumns() - round key: b692cf0b643dbdf1be9bc5006830b3fe - state: 4915598f55e5d7a0daca94fa1f0a63f7 <-- AddRoundKey() - -Round 3: - state: 3b59cb73fcd90ee05774222dc067fb68 <-- SubBytes() - state: 3bd92268fc74fb735767cbe0c0590e2d <-- ShiftRows() - state: 4c9c1e66f771f0762c3f868e534df256 <-- MixColumns() - round key: b6ff744ed2c2c9bf6c590cbf0469bf41 - state: fa636a2825b339c940668a3157244d17 <-- AddRoundKey() - -Round 4: - state: 2dfb02343f6d12dd09337ec75b36e3f0 <-- SubBytes() - state: 2d6d7ef03f33e334093602dd5bfb12c7 <-- ShiftRows() - state: 6385b79ffc538df997be478e7547d691 <-- MixColumns() - round key: 47f7f7bc95353e03f96c32bcfd058dfd - state: 247240236966b3fa6ed2753288425b6c <-- AddRoundKey() - -Round 5: - state: 36400926f9336d2d9fb59d23c42c3950 <-- SubBytes() - state: 36339d50f9b539269f2c092dc4406d23 <-- ShiftRows() - state: f4bcd45432e554d075f1d6c51dd03b3c <-- MixColumns() - round key: 3caaa3e8a99f9deb50f3af57adf622aa - state: c81677bc9b7ac93b25027992b0261996 <-- AddRoundKey() - -Round 6: - state: e847f56514dadde23f77b64fe7f7d490 <-- SubBytes() - state: e8dab6901477d4653ff7f5e2e747dd4f <-- ShiftRows() - state: 9816ee7400f87f556b2c049c8e5ad036 <-- MixColumns() - round key: 5e390f7df7a69296a7553dc10aa31f6b - state: c62fe109f75eedc3cc79395d84f9cf5d <-- AddRoundKey() - -Round 7: - state: b415f8016858552e4bb6124c5f998a4c <-- SubBytes() - state: b458124c68b68a014b99f82e5f15554c <-- ShiftRows() - state: c57e1c159a9bd286f05f4be098c63439 <-- MixColumns() - round key: 14f9701ae35fe28c440adf4d4ea9c026 - state: d1876c0f79c4300ab45594add66ff41f <-- AddRoundKey() - -Round 8: - state: 3e175076b61c04678dfc2295f6a8bfc0 <-- SubBytes() - state: 3e1c22c0b6fcbf768da85067f6170495 <-- ShiftRows() - state: baa03de7a1f9b56ed5512cba5f414d23 <-- MixColumns() - round key: 47438735a41c65b9e016baf4aebf7ad2 - state: fde3bad205e5d0d73547964ef1fe37f1 <-- AddRoundKey() - -Round 9: - state: 5411f4b56bd9700e96a0902fa1bb9aa1 <-- SubBytes() - state: 54d990a16ba09ab596bbf40ea111702f <-- ShiftRows() - state: e9f74eec023020f61bf2ccf2353c21c7 <-- MixColumns() - round key: 549932d1f08557681093ed9cbe2c974e - state: bd6e7c3df2b5779e0b61216e8b10b689 <-- AddRoundKey() - -Round 10: - state: 7a9f102789d5f50b2beffd9f3dca4ea7 <-- SubBytes() - state: 7ad5fda789ef4e272bca100b3d9ff59f <-- ShiftRows() - round key: 13111d7fe3944a17f307a78b4d2b30c5 - ciphertext: 69c4e0d86a7b0430d8cdb78070b4c55a <-- AddRoundKey() - */ diff --git a/korge-foundation/test/korlibs/crypto/Base64Test.kt b/korge-foundation/test/korlibs/crypto/Base64Test.kt deleted file mode 100644 index f2c67b43ba..0000000000 --- a/korge-foundation/test/korlibs/crypto/Base64Test.kt +++ /dev/null @@ -1,44 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.Base64 -import korlibs.encoding.fromBase64 -import korlibs.encoding.toBase64 -import kotlin.test.Test -import kotlin.test.assertEquals - -class Base64Test { - @Test - fun name() { - assertEquals("AQID", Base64.encode(byteArrayOf(1, 2, 3))) - assertEquals("aGVsbG8=", Base64.encode("hello".encodeToByteArray())) - assertEquals(byteArrayOf(1, 2, 3).toList(), Base64.decode("AQID").toList()) - assertEquals("hello", Base64.decode("aGVsbG8=").decodeToString()) - } - - @Test - fun testSeveral() { - for (item in listOf("", "a", "aa", "aaa", "aaaa", "aaaaa", "Hello World!")) { - assertEquals(item, item.encodeToByteArray().toBase64().fromBase64().decodeToString()) - } - } - - @Test - fun testGlobal() { - assertEquals("hello", globalBase64) - assertEquals("hello", ObjectBase64.globalBase64) - } - - @Test - fun testIssue64DecodeWithMissingPadding() { - assertEquals( - "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ==", - Base64.encode(Base64.decode("eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ")) - ) - } -} - -object ObjectBase64 { - val globalBase64 = "aGVsbG8=".fromBase64().decodeToString() -} - -val globalBase64 = "aGVsbG8=".fromBase64().decodeToString() diff --git a/korge-foundation/test/korlibs/crypto/Base64UrlTest.kt b/korge-foundation/test/korlibs/crypto/Base64UrlTest.kt deleted file mode 100644 index 697a156c80..0000000000 --- a/korge-foundation/test/korlibs/crypto/Base64UrlTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.Base64 -import korlibs.encoding.fromBase64 -import korlibs.encoding.toBase64 -import kotlin.test.Test -import kotlin.test.assertEquals - -class Base64UrlTest { - @Test - fun name() { - assertEquals("AQID", Base64.encode(byteArrayOf(1, 2, 3), true)) - assertEquals("aGVsbG8", Base64.encode("hello".encodeToByteArray(), true)) - assertEquals(byteArrayOf(1, 2, 3).toList(), Base64.decode("AQID", true).toList()) - assertEquals("hello", Base64.decode("aGVsbG8", true).decodeToString()) - } - - @Test - fun testSeveral() { - for (item in listOf("", "a", "aa", "aaa", "aaaa", "aaaaa", "Hello World!")) { - assertEquals( - item, - item.encodeToByteArray().toBase64(true).fromBase64(ignoreSpaces = false, url = true).decodeToString() - ) - } - } - - @Test - fun testGlobal() { - assertEquals("hello", globalBase64Url) - assertEquals("hello", ObjectBase64Url.globalBase64) - } - - @Test - fun testIssue64DecodeWithMissingPadding() { - assertEquals( - "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ", - Base64.encode( - Base64.decode( - "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ", - url = true - ), - url = true, - doPadding = false - ) - ) - } - - @Test - fun testIssue64DecodeWithPadding() { - assertEquals( - "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ==", - Base64.encode( - Base64.decode( - "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ==", - url = true - ), - url = true, - doPadding = true - ) - ) - } -} - -object ObjectBase64Url { - val globalBase64 = "aGVsbG8".fromBase64(ignoreSpaces = true, url = true).decodeToString() -} - -val globalBase64Url = "aGVsbG8".fromBase64(ignoreSpaces = true, url = true).decodeToString() diff --git a/korge-foundation/test/korlibs/crypto/CipherTest.kt b/korge-foundation/test/korlibs/crypto/CipherTest.kt deleted file mode 100644 index 50eaac1c24..0000000000 --- a/korge-foundation/test/korlibs/crypto/CipherTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.Hex -import korlibs.encoding.hexLower -import kotlin.test.Test -import kotlin.test.assertEquals - -class CipherTest { - @Test - fun testAes() { - val plainText = Hex.decode("00112233445566778899aabbccddeeff") - val cipherKey = Hex.decode("000102030405060708090a0b0c0d0e0f") - val cipherText = Hex.decode("69c4e0d86a7b0430d8cdb78070b4c55a") - val encryptor = AES(cipherKey)[CipherMode.ECB, Padding.NoPadding] - assertEquals(cipherText.hexLower, encryptor.encrypt(plainText).hexLower) - } -} diff --git a/korge-foundation/test/korlibs/crypto/HMACTest.kt b/korge-foundation/test/korlibs/crypto/HMACTest.kt deleted file mode 100644 index 219e58319e..0000000000 --- a/korge-foundation/test/korlibs/crypto/HMACTest.kt +++ /dev/null @@ -1,74 +0,0 @@ -package korlibs.crypto - -import kotlin.test.Test -import kotlin.test.assertEquals - -class HMACTest { - @Test - fun hmacSHA1() { - val data = ByteArray(16){(it + 1).toByte()} - - var key = ByteArray(10){it.toByte()} // key length lt chunk size - var mac = HMAC.hmacSHA1(key, data) - assertEquals("976a1c6879bc6e776752c254343431bcdc46f298", mac.hex) - - key = ByteArray(64){it.toByte()} // key length eq chunk size - mac = HMAC.hmacSHA1(key, data) - assertEquals("322af17f50bfa006ecae7cab356d2ba1f8517f8f", mac.hex) - - key = ByteArray(120){it.toByte()} // key length gt chunk size - mac = HMAC.hmacSHA1(key, data) - assertEquals("3123c313a25aab46b56b873730291a57783d8dce", mac.hex) - } - - @Test - fun hmacSHA256() { - val data = ByteArray(16){(it + 1).toByte()} - - var key = ByteArray(10){it.toByte()} // key length lt chunk size - var mac = HMAC.hmacSHA256(key, data) - assertEquals("4d4b24f0ac17843f1797609b6acb67acbb72b04775c6186a62b69db8b6fc00af", mac.hex) - - key = ByteArray(64){it.toByte()} // key length eq chunk size - mac = HMAC.hmacSHA256(key, data) - assertEquals("1b0646619ebcdde1fbb754f23182f26da3067e0689c27b928040271bf1848a33", mac.hex) - - key = ByteArray(120){it.toByte()} // key length gt chunk size - mac = HMAC.hmacSHA256(key, data) - assertEquals("c8bdca76e9e2257a5e7b26f4d9f1eee7e21fcea098e2255288a32ca0c19ae605", mac.hex) - } - - @Test - fun hmacSHA512() { - val data = ByteArray(16){(it + 1).toByte()} - - var key = ByteArray(10){it.toByte()} // key length lt chunk size - var mac = HMAC.hmacSHA512(key, data) - assertEquals("b65aa1ddecc30fb251219d2ded1831db73a8dea36c304f640c1df7479d356b5cf908914000a438a7d6704420ec96727966166785e5d2ea3f7c05005911722b92", mac.hex) - - key = ByteArray(128){it.toByte()} // key length eq chunk size - mac = HMAC.hmacSHA512(key, data) - assertEquals("4be6f955033d290e6a054143d1fe92b9badc827f7f87a4373189538a9bb7cd40670cc54d4787d0dcb2c61f6b24b5841581c23a3da82239c6436ce04f397109c5", mac.hex) - - key = ByteArray(136){it.toByte()} // key length gt chunk size - mac = HMAC.hmacSHA512(key, data) - assertEquals("4043b5f4151a8e5aaedb7ea9efa452f872d43f850f9c5a8670ca1bf4e7214419129e53a51dfc641a5758cd5b72d21f17ad5f9391303d3ef91f6b074aa943c41c", mac.hex) - } - - @Test - fun hmacMD5() { - val data = ByteArray(16){(it + 1).toByte()} - - var key = ByteArray(10){it.toByte()} // key length lt chunk size - var mac = HMAC.hmacMD5(key, data) - assertEquals("ed082a8955ccb35ced1dd4fa3372f08e", mac.hex) - - key = ByteArray(64){it.toByte()} // key length eq chunk size - mac = HMAC.hmacMD5(key, data) - assertEquals("ad6a2aefac457cb561d5e43066f3dc8b", mac.hex) - - key = ByteArray(120){it.toByte()} // key length gt chunk size - mac = HMAC.hmacMD5(key, data) - assertEquals("e34ada41811e232eeeaf9b3a1a1bf0d1", mac.hex) - } -} diff --git a/korge-foundation/test/korlibs/crypto/MD4Test.kt b/korge-foundation/test/korlibs/crypto/MD4Test.kt deleted file mode 100644 index c37e5c0485..0000000000 --- a/korge-foundation/test/korlibs/crypto/MD4Test.kt +++ /dev/null @@ -1,35 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.ASCII -import kotlin.test.Test -import kotlin.test.assertEquals - -class MD4Test { - @Test - fun testEmpty() { - assertEquals("31d6cfe0d16ae931b73c59d7e0c089c0", MD4.digest(ASCII("")).hex) - } - - @Test - fun test1() { - assertEquals("bde52cb31de33e46245e05fbdbd6fb24", MD4.digest(ASCII("a")).hex) - - assertEquals("bde52cb31de33e46245e05fbdbd6fb24", ASCII("a").hash(MD4).hex) - assertEquals("bde52cb31de33e46245e05fbdbd6fb24", ASCII("a").md4().hex) - } - - @Test - fun test2() { - assertEquals("52f5076fabd22680234a3fa9f9dc5732", MD4.digest(ByteArray(64) { 'a'.toByte() }).hex) - } - - @Test - fun test3() { - assertEquals("a448017aaf21d8525fc10ae87aa6729d", MD4.digest(ASCII("abc")).hex) - assertEquals("a448017aaf21d8525fc10ae87aa6729d", MD4().update(ASCII("a")).update(ASCII("bc")).digest().hex) - assertEquals("d9130a8164549fe818874806e1c7014b", MD4.digest(ASCII("message digest")).hex) - assertEquals("d79e1c308aa5bbcdeea8ed63df412da9", MD4.digest(ASCII("abcdefghijklmnopqrstuvwxyz")).hex) - assertEquals("043f8582f241db351ce627e153e7f0e4", MD4.digest(ASCII("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")).hex) - assertEquals("e33b4ddc9c38f2199c3e7b164fcc0536", MD4.digest(ASCII("12345678901234567890123456789012345678901234567890123456789012345678901234567890")).hex) - } -} diff --git a/korge-foundation/test/korlibs/crypto/MD5Test.kt b/korge-foundation/test/korlibs/crypto/MD5Test.kt deleted file mode 100644 index 65dda11766..0000000000 --- a/korge-foundation/test/korlibs/crypto/MD5Test.kt +++ /dev/null @@ -1,35 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.ASCII -import kotlin.test.Test -import kotlin.test.assertEquals - -class MD5Test { - @Test - fun testEmpty() { - assertEquals("d41d8cd98f00b204e9800998ecf8427e", MD5.digest(ASCII("")).hex) - } - - @Test - fun test1() { - assertEquals("0cc175b9c0f1b6a831c399e269772661", MD5.digest(ASCII("a")).hex) - - assertEquals("0cc175b9c0f1b6a831c399e269772661", ASCII("a").hash(MD5).hex) - assertEquals("0cc175b9c0f1b6a831c399e269772661", ASCII("a").md5().hex) - } - - @Test - fun test2() { - assertEquals("014842d480b571495a4a0363793f7367", MD5.digest(ByteArray(64) { 'a'.toByte() }).hex) - } - - @Test - fun test3() { - assertEquals("900150983cd24fb0d6963f7d28e17f72", MD5.digest(ASCII("abc")).hex) - assertEquals("900150983cd24fb0d6963f7d28e17f72", MD5().update(ASCII("a")).update(ASCII("bc")).digest().hex) - assertEquals("f96b697d7cb7938d525a2f31aaf161d0", MD5.digest(ASCII("message digest")).hex) - assertEquals("c3fcd3d76192e4007dfb496cca67e13b", MD5.digest(ASCII("abcdefghijklmnopqrstuvwxyz")).hex) - assertEquals("d174ab98d277d9f5a5611c2c9f419d9f", MD5.digest(ASCII("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")).hex) - assertEquals("57edf4a22be3c955ac49da2e2107b67a", MD5.digest(ASCII("12345678901234567890123456789012345678901234567890123456789012345678901234567890")).hex) - } -} diff --git a/korge-foundation/test/korlibs/crypto/PBKDF2Test.kt b/korge-foundation/test/korlibs/crypto/PBKDF2Test.kt deleted file mode 100644 index ee6bd3e22f..0000000000 --- a/korge-foundation/test/korlibs/crypto/PBKDF2Test.kt +++ /dev/null @@ -1,42 +0,0 @@ -package korlibs.crypto - -import kotlin.test.Test -import kotlin.test.assertEquals - -class PBKDF2Test { - @Test - fun pbkdf2WithHmacSHA1() { - val password = byteArrayOf(65, 66, 67, 68, 69, 70, 71, 72) // [A, B, C, D, E, F, G, H] - val salt = ByteArray(12){(it + 1).toByte()} - val iterationCount = 128 - val keyLength = 256 - assertEquals( - "506a8102a74cc4732cfbce262f07e09ff6a36b9ae98dc1491302a8b6dfbf9e00", - PBKDF2.pbkdf2WithHmacSHA1(password, salt, iterationCount, keyLength).hex - ) - } - - @Test - fun pbkdf2WithHmacSHA256() { - val password = byteArrayOf(65, 66, 67, 68, 69, 70, 71, 72) // [A, B, C, D, E, F, G, H] - val salt = ByteArray(12){(it + 1).toByte()} - val iterationCount = 128 - val keyLength = 256 - assertEquals( - "c8b80edacfe754d8fceaa97a4756818aebded276ce832ee8fc39d2e8fd2f6d8f", - PBKDF2.pbkdf2WithHmacSHA256(password, salt, iterationCount, keyLength).hex - ) - } - - @Test - fun pbkdf2WithHmacSHA512() { - val password = "password".encodeToByteArray() - val salt = ByteArray(12) { (it + 1).toByte() } - val iterationCount = 128 - val keyLength = 256 - assertEquals( - "846a7cc6612ba20651e4dd8513b2e71e3e45d983561d9a5123b17d42df5aeabe", - PBKDF2.pbkdf2WithHmacSHA512(password, salt, iterationCount, keyLength).hex, - ) - } -} diff --git a/korge-foundation/test/korlibs/crypto/SHA1Test.kt b/korge-foundation/test/korlibs/crypto/SHA1Test.kt deleted file mode 100644 index e45d352feb..0000000000 --- a/korge-foundation/test/korlibs/crypto/SHA1Test.kt +++ /dev/null @@ -1,31 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.ASCII -import kotlin.test.Test -import kotlin.test.assertEquals - -class SHA1Test { - @Test - fun name() { - assertEquals("da39a3ee5e6b4b0d3255bfef95601890afd80709", SHA1.digest(ASCII("")).hex) - assertEquals("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", SHA1.digest(ASCII("a")).hex) - assertEquals( - "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", - SHA1.digest(ASCII("abcdefghijklmnopqrstuvwxyz")).hex - ) - - assertEquals("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", ASCII("a").hash(SHA1).hex) - assertEquals("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", ASCII("a").sha1().hex) - } - - @Test - fun testReset() { - val sha1 = SHA1() - sha1.update(ByteArray(16)) - assertEquals(ByteArray(16).sha1().hex, sha1.digest().hex) - - sha1.reset() - sha1.update(ByteArray(20)) - assertEquals(ByteArray(20).sha1().hex, sha1.digest().hex) - } -} diff --git a/korge-foundation/test/korlibs/crypto/SHA256Test.kt b/korge-foundation/test/korlibs/crypto/SHA256Test.kt deleted file mode 100644 index a76b4eb1d3..0000000000 --- a/korge-foundation/test/korlibs/crypto/SHA256Test.kt +++ /dev/null @@ -1,26 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.ASCII -import kotlin.test.Test -import kotlin.test.assertEquals - -class SHA256Test { - @Test - fun test() { - assertEquals("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", SHA256.digest(byteArrayOf()).hex) - } - - @Test - fun test2() { - assertEquals("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb", SHA256.digest(ByteArray(64) { 'a'.toByte() }).hex) - - assertEquals("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb", ByteArray(64) { 'a'.toByte() }.hash(SHA256).hex) - assertEquals("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb", ByteArray(64) { 'a'.toByte() }.sha256().hex) - } - - @Test - fun test3() { - assertEquals("d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", SHA256.digest(ASCII("The quick brown fox jumps over the lazy dog")).hex) - assertEquals("539deb4a951195ca3377514b8a44b95061b4fcd5ae21b29be3748cc835992b52", SHA256.digest(ASCII("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")).hex) - } -} diff --git a/korge-foundation/test/korlibs/crypto/SHA512Test.kt b/korge-foundation/test/korlibs/crypto/SHA512Test.kt deleted file mode 100644 index 094b851f87..0000000000 --- a/korge-foundation/test/korlibs/crypto/SHA512Test.kt +++ /dev/null @@ -1,61 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.ASCII -import kotlin.test.Test -import kotlin.test.assertEquals - -class SHA512Test { - @Test - fun testRawEmpty() { - val out = ByteArray(64) - val sha = SHA512() - sha.reset() - sha.update(byteArrayOf(), 0, 0) - sha.digestOut(out) - assertEquals( - "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", - Hash(out).hexLower - ) - } - - @Test - fun testEmpty() { - assertEquals( - "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", - SHA512.digest("".encodeToByteArray()).hexLower - ) - } - - @Test - fun testA() { - assertEquals( - "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", - SHA512.digest("a".encodeToByteArray()).hexLower - ) - } - - @Test - fun test2() { - assertEquals("01d35c10c6c38c2dcf48f7eebb3235fb5ad74a65ec4cd016e2354c637a8fb49b695ef3c1d6f7ae4cd74d78cc9c9bcac9d4f23a73019998a7f73038a5c9b2dbde", SHA512.digest(ByteArray(64) { 'a'.toByte() }).hex) - assertEquals("01d35c10c6c38c2dcf48f7eebb3235fb5ad74a65ec4cd016e2354c637a8fb49b695ef3c1d6f7ae4cd74d78cc9c9bcac9d4f23a73019998a7f73038a5c9b2dbde", ByteArray(64) { 'a'.toByte() }.hash(SHA512).hex) - assertEquals("01d35c10c6c38c2dcf48f7eebb3235fb5ad74a65ec4cd016e2354c637a8fb49b695ef3c1d6f7ae4cd74d78cc9c9bcac9d4f23a73019998a7f73038a5c9b2dbde", ByteArray(64) { 'a'.toByte() }.sha512().hex) - } - - @Test - fun test3() { - assertEquals("07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6", SHA512.digest(ASCII("The quick brown fox jumps over the lazy dog")).hex) - assertEquals("753c07c6245748d0002359efb1018687880219eb5f10b0015362ba80679589b1679e87dfdba276b2fbcbf8e48377270ddfe99c9ba7b4cbc6763ecd55f9fb1b7d", SHA512.digest(ASCII("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")).hex) - } - - @Test - fun test4() { - assertEquals("c82fb0cc171015e9b1c95c912b17b30cfa76c637260cca09e78fdaf1d4dbe9b2d08501b7af8b48cb8bdb02d6e9ca2662971c0f23fd8c5c02c33e6a8f72df5028", "a".repeat(1311).encodeToByteArray().sha512().hex) - } - - @Test - fun test5() { - for (n in 0 until 257) { - ByteArray(n) { n.toByte() }.sha512().hex - } - } -} diff --git a/korge-foundation/test/korlibs/crypto/SecureRandomTest.kt b/korge-foundation/test/korlibs/crypto/SecureRandomTest.kt deleted file mode 100644 index b52b4c5af7..0000000000 --- a/korge-foundation/test/korlibs/crypto/SecureRandomTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package korlibs.crypto - -import kotlin.test.Test -import kotlin.test.Ignore -import kotlin.test.assertNotEquals - -class SecureRandomTest { - @Test - fun test() { - SecureRandom.addSeed(byteArrayOf(1, 2, 3)) // This shouldn't reduce entropy - println(SecureRandom.nextBytes(15).toList()) - println(SecureRandom.nextBytes(15).toList()) - assertNotEquals(SecureRandom.nextBytes(16).toList(), SecureRandom.nextBytes(16).toList()) - assertNotEquals(SecureRandom.nextBytes(16).toList(), SecureRandom.nextBytes(16).toList()) - println(SecureRandom.nextBytes(15).toList()) - } -} diff --git a/korge-foundation/test@jvm/korlibs/crypto/AESJvmTest.kt b/korge-foundation/test@jvm/korlibs/crypto/AESJvmTest.kt deleted file mode 100644 index 70155d83ed..0000000000 --- a/korge-foundation/test@jvm/korlibs/crypto/AESJvmTest.kt +++ /dev/null @@ -1,76 +0,0 @@ -package korlibs.crypto - -import korlibs.encoding.* -import javax.crypto.spec.* -import kotlin.test.* - -class AESJvmTest { - val MODES = listOf( - CipherMode.ECB, - CipherMode.CBC, - CipherMode.PCBC, - CipherMode.CFB, - CipherMode.OFB, - CipherMode.CTR, - ) - - @Test - fun testSimple() { - val key = SecureRandom.nextBytes(16) - val iv = SecureRandom.nextBytes(16) - val plain = ByteArray(32) { it.toByte() } - val encrypted = encryptJava("AES", "CTR", "NoPadding", plain, key, iv) - val decrypted = decryptJava("AES", "CTR", "NoPadding", encrypted, key, iv) - assertEquals(plain.hex, decrypted.hex) - } - - @Test - fun testCompareOurImpl() { - val key = ByteArray(16) { (it * 3).toByte() } - val iv = ByteArray(16) { (it * 7).toByte() } - val ivCopy = iv.copyOf() - val plain = ByteArray(32) { it.toByte() } - val plainCopy = plain.copyOf() - - for (mode in MODES) { - val crypt = AES(key)[mode, CipherPadding.NoPadding, iv] - val algo = "AES" - val padding = "NoPadding" - val encryptedJava = encryptJava(algo, mode.name, padding, plain, key, iv) - val encryptedOur = crypt.encrypt(plain) - val encryptedCopy = encryptedOur.copyOf() - - val decryptedJava = decryptJava(algo, mode.name, padding, encryptedJava, key, iv) - val decryptedOur = crypt.decrypt(encryptedOur) - - // No mutating inputs - assertEquals(encryptedCopy.hex, encryptedOur.hex, "encrypted shouldn't be modified") - assertEquals(plainCopy.hex, plain.hex, "plain shouldn't be modified") - assertEquals(ivCopy.hex, iv.hex, "iv shouldn't be modified") - - assertEquals(encryptedJava.hex, encryptedOur.hex, "Failed encrypted java-our ${mode.name}") - assertEquals(decryptedJava.hex, decryptedOur.hex, "Failed decrypted java-our ${mode.name}") - assertEquals(plain.hex, decryptedOur.hex, "Failed plain-decrypted ${mode.name}") - } - } - - private fun encryptJava(algo: String, mode: String, padding: String, data: ByteArray, key: ByteArray = SecureRandom.nextBytes(16), iv: ByteArray = SecureRandom.nextBytes(16)): ByteArray { - return encryptDecryptJava(javax.crypto.Cipher.ENCRYPT_MODE, algo, mode, padding, data, key, iv) - } - - private fun decryptJava(algo: String, mode: String, padding: String, data: ByteArray, key: ByteArray = SecureRandom.nextBytes(16), iv: ByteArray = SecureRandom.nextBytes(16)): ByteArray { - return encryptDecryptJava(javax.crypto.Cipher.DECRYPT_MODE, algo, mode, padding, data, key, iv) - } - - private fun encryptDecryptJava(emode: Int, algo: String, mode: String, padding: String, data: ByteArray, key: ByteArray = SecureRandom.nextBytes(16), iv: ByteArray = SecureRandom.nextBytes(16)): ByteArray { - return javax.crypto.Cipher.getInstance("$algo/$mode/$padding").let { cipher -> - val keySpec = SecretKeySpec(key, algo) - if (mode == "ECB") { - cipher.init(emode, keySpec) - } else { - cipher.init(emode, keySpec, IvParameterSpec(iv)) - } - cipher.doFinal(data) - } - } -} diff --git a/korge-foundation/test@jvm/korlibs/crypto/PBKDF2JvmTest.kt b/korge-foundation/test@jvm/korlibs/crypto/PBKDF2JvmTest.kt deleted file mode 100644 index 74f789049e..0000000000 --- a/korge-foundation/test@jvm/korlibs/crypto/PBKDF2JvmTest.kt +++ /dev/null @@ -1,98 +0,0 @@ -package korlibs.crypto - -import org.junit.Test -import java.security.MessageDigest -import javax.crypto.SecretKeyFactory -import javax.crypto.spec.PBEKeySpec -import kotlin.test.assertEquals - -class PBKDF2JvmTest { - companion object { - //const val DEFAULT_ITERATION_COUNT = 4096 - const val DEFAULT_ITERATION_COUNT = 128 - } - - fun generateJVM( - kind: HasherFactory, password: ByteArray, keyLength: Int, iterationCount: Int, salt: ByteArray - ): Hash { - return Hash(SecretKeyFactory.getInstance("PBKDF2WithHmac${kind.name}").generateSecret( - PBEKeySpec(password.map { it.toInt().toChar() }.toCharArray(), salt, iterationCount, keyLength) - ).encoded) - } - - fun generateKrypto( - kind: HasherFactory, password: ByteArray, keyLength: Int, iterationCount: Int, salt: ByteArray - ): Hash { - return PBKDF2.pbkdf2(password, salt, iterationCount, keyLength, kind()) - } - - fun checkAlgo( - kind: HasherFactory, - password: ByteArray = byteArrayOf(65, 66, 67, 68, 69, 70, 71, 72), - keyLength: Int = 256, - iterationCount: Int = DEFAULT_ITERATION_COUNT, - salt: ByteArray = ByteArray(12) { (it + 1).toByte() } - ) { - val jvm = generateJVM(kind, password, keyLength, iterationCount, salt) - val krypto = generateKrypto(kind, password, keyLength, iterationCount, salt) - //println("${kind.name}: ${password.decodeToString()}, $krypto") - assertEquals(jvm, krypto) - } - - @Test - fun pbkdf2WithHmacSHA1() { - checkAlgo(SHA1) - checkAlgo(SHA1, password = "password".encodeToByteArray()) - } - - @Test - fun pbkdf2WithHmacSHA256() { - checkAlgo(SHA256) - checkAlgo(SHA256, password = "password".encodeToByteArray()) - } - - @Test - fun pbkdf2WithHmacSHA512() { - checkAlgo(SHA512) - checkAlgo(SHA512, password = "password".encodeToByteArray()) - } - - @Test - fun pbkdf2WithHmacJavaSHA1() { - checkAlgo(JavaSHA.Factory(1)) - checkAlgo(JavaSHA.Factory(1), password = "password".encodeToByteArray()) - } - - @Test - fun pbkdf2WithHmacJavaSHA256() { - checkAlgo(JavaSHA.Factory(256)) - checkAlgo(JavaSHA.Factory(256), password = "password".encodeToByteArray()) - } - - @Test - fun pbkdf2WithHmacJavaSHA512() { - checkAlgo(JavaSHA.Factory(512)) - checkAlgo(JavaSHA.Factory(512), password = "password".encodeToByteArray()) - } - - class JavaSHA( - val size: Int, - val md: MessageDigest = MessageDigest.getInstance("SHA-$size") - ) : NonCoreHasher(if (size == 512) 128 else 64, md.digestLength, "SHA$size") { - class Factory(size: Int) : HasherFactory("SHA$size", { JavaSHA(size) }) - - override fun reset(): Hasher { - md.reset() - return this - } - - override fun update(data: ByteArray, offset: Int, count: Int): Hasher { - md.update(data, offset, count) - return this - } - - override fun digestOut(out: ByteArray) { - md.digest().copyInto(out, 0, 0, out.size) - } - } -} diff --git a/korge-foundation/test@jvm/korlibs/crypto/SHA512JvmTest.kt b/korge-foundation/test@jvm/korlibs/crypto/SHA512JvmTest.kt deleted file mode 100644 index dfe7fc42fe..0000000000 --- a/korge-foundation/test@jvm/korlibs/crypto/SHA512JvmTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -package korlibs.crypto - -import java.security.MessageDigest -import kotlin.test.Test -import kotlin.test.assertEquals - - -class SHA512JvmTest { - @Test - fun test() { - for (n in 0 until 1033) { - compareHash(ByteArray(n) { n.toByte() }) - } - } - - private fun compareHash(data: ByteArray) { - assertEquals(data.sha512jvm(), data.sha512()) - } - - private fun ByteArray.sha512jvm(): Hash { - val digest: MessageDigest = MessageDigest.getInstance("SHA-512") - digest.reset() - digest.update(this) - return Hash(digest.digest()) - } -} diff --git a/korlibs-crypto/src/korlibs/bignumber/BigInt.kt b/korlibs-crypto/src/korlibs/bignumber/BigInt.kt index 025ec968fc..4451f86b9b 100644 --- a/korlibs-crypto/src/korlibs/bignumber/BigInt.kt +++ b/korlibs-crypto/src/korlibs/bignumber/BigInt.kt @@ -1,21 +1,13 @@ package korlibs.bignumber -import korlibs.bignumber.ranges.* - // Big Integer /** Converts this into a [BigInt] */ -val Long.bi: BigInt get() = BigInt(this) -/** Converts this into a [BigInt] */ -val Int.bi: BigInt get() = BigInt(this) -/** Converts this into a [BigInt] */ -val String.bi: BigInt get() = BigInt(this) -/** Converts this into a [BigInt] using a specific [radix], that is the base to use. radix=10 for decimal, radix=16 for hexadecimal */ -fun String.bi(radix: Int): BigInt = BigInt(this, radix) +internal val Int.internalCryptoBI: BigInt get() = BigInt(this) /** * Represents an arbitrary-sized Big Integer. */ -interface BigInt : Comparable, BigIntConstructor { +internal interface BigInt : Comparable, BigIntConstructor { companion object { val usesNativeImplementation get() = BigInt(0) !is CommonBigInt @@ -103,19 +95,16 @@ interface BigInt : Comparable, BigIntConstructor { operator fun div(other: Int): BigInt = this / create(other) /** Returns this % [other] */ operator fun rem(other: Int): BigInt = this % create(other) - - /** Creates a new inclusive [BigIntRange] ranging from [this] to [that] */ - operator fun rangeTo(that: BigInt): BigIntRange = BigIntRange(start = this, endInclusive = that) } -interface BigIntCompanion : BigIntConstructor { +internal interface BigIntCompanion : BigIntConstructor { operator fun invoke(value: Int) = create(value) operator fun invoke(value: Long) = create(value) operator fun invoke(value: String) = create(value) operator fun invoke(value: String, radix: Int) = create(value, radix) } -interface BigIntConstructor { +internal interface BigIntConstructor { fun create(value: Int): BigInt //fun create(value: Long): BigInt = create("$value", 10) // @TODO: Kotlin.JS BUG fun create(value: Long): BigInt { @@ -166,12 +155,12 @@ interface BigIntConstructor { } } -expect val BigIntNativeFactory: BigIntConstructor +internal expect val InternalCryptoBigIntNativeFactory: BigIntConstructor -fun BigInt(value: Int): BigInt = BigIntNativeFactory.create(value) -fun BigInt(value: Long): BigInt = BigIntNativeFactory.create(value) -fun BigInt(value: String, radix: Int): BigInt = BigIntNativeFactory.create(value, radix) -fun BigInt(value: String): BigInt = BigIntNativeFactory.create(value) +internal fun BigInt(value: Int): BigInt = InternalCryptoBigIntNativeFactory.create(value) +internal fun BigInt(value: Long): BigInt = InternalCryptoBigIntNativeFactory.create(value) +internal fun BigInt(value: String, radix: Int): BigInt = InternalCryptoBigIntNativeFactory.create(value, radix) +internal fun BigInt(value: String): BigInt = InternalCryptoBigIntNativeFactory.create(value) internal fun parseWithNumberPrefix(str: String, gen: (sub: String, radix: Int) -> T): T = when { str.startsWith("0x") -> gen(str.substring(2), 16) @@ -181,12 +170,12 @@ internal fun parseWithNumberPrefix(str: String, gen: (sub: String, radix: In } /** A generic [BigInt] exception */ -open class BigIntException(message: String) : Throwable(message) +internal open class BigIntException(message: String) : Throwable(message) /** A [BigInt] exception thrown when an invalid String value is provided while parsing */ -open class BigIntInvalidFormatException(message: String) : BigIntException(message) +internal open class BigIntInvalidFormatException(message: String) : BigIntException(message) /** A [BigInt] exception thrown when trying to divide by zero */ -open class BigIntDivisionByZeroException() : BigIntException("Division by zero") +internal open class BigIntDivisionByZeroException() : BigIntException("Division by zero") /** A [BigInt] exception thrown when an overflow operation occurs, like for example when trying to convert a too big [BigInt] into an [Int] */ -open class BigIntOverflowException(message: String) : BigIntException(message) +internal open class BigIntOverflowException(message: String) : BigIntException(message) /** A [BigInt] exception thrown when doing a `pow` operation with a negative exponent */ -open class BigIntNegativeExponentException() : BigIntOverflowException("Negative exponent") +internal open class BigIntNegativeExponentException() : BigIntOverflowException("Negative exponent") diff --git a/korlibs-crypto/src/korlibs/bignumber/BigNum.kt b/korlibs-crypto/src/korlibs/bignumber/BigNum.kt index 527e70c3af..d84a5f41b7 100644 --- a/korlibs-crypto/src/korlibs/bignumber/BigNum.kt +++ b/korlibs-crypto/src/korlibs/bignumber/BigNum.kt @@ -1,36 +1,21 @@ package korlibs.bignumber -import korlibs.bignumber.ranges.* import kotlin.math.* -// Big Number -/** Converts this into a [BigNum] */ -val Double.bn: BigNum get() = BigNum("$this") -/** Converts this into a [BigNum] */ -val Long.bn: BigNum get() = BigNum(this.bi, 0) -/** Converts this into a [BigNum] */ -val Int.bn: BigNum get() = BigNum(this.bi, 0) -/** Converts this into a [BigNum] */ -val String.bn: BigNum get() = BigNum(this) - /** * Represents a [BigNum], * a numeric value with decimal places that is exact. * * There are no precision issues like happens with [Float] or [Double] floating point types. */ -class BigNum(val int: BigInt, val scale: Int) : Comparable { +internal class BigNum(val int: BigInt, val scale: Int) : Comparable { init { //println("BigNum($int, $scale) == $this") } companion object { - /** Represents 0.0 as a [BigNum] */ - val ZERO = BigNum(BigInt(0), 0) /** Represents 1.0 as a [BigNum] */ val ONE = BigNum(BigInt(1), 0) - /** Represents 2.0 as a [BigNum] */ - val TWO = BigNum(BigInt(2), 0) /** Creates a [BigNum] from a string [str] */ operator fun invoke(str: String): BigNum { @@ -60,8 +45,8 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable { */ fun convertToScale(otherScale: Int): BigNum = when { this.scale == otherScale -> this - otherScale > this.scale -> BigNum(int * (10.bi pow (otherScale - this.scale)), otherScale) - else -> BigNum(int / (10.bi pow (this.scale - otherScale)), otherScale) + otherScale > this.scale -> BigNum(int * (10.internalCryptoBI pow (otherScale - this.scale)), otherScale) + else -> BigNum(int / (10.internalCryptoBI pow (this.scale - otherScale)), otherScale) } /** Performs this + [other] returning a [BigNum], if the scale is different for both numbers, it finds a common one */ @@ -78,11 +63,11 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable { /** Performs this / [other] returning a [BigNum] using a specific [precision] */ fun div(other: BigNum, precision: Int): BigNum { - val scale = (10.bi pow (other.scale + precision)) + val scale = (10.internalCryptoBI pow (other.scale + precision)) val li = this.int * scale val ri = other.int val res = li / ri - return BigNum(res, this.scale) * BigNum(1.bi, precision) + return BigNum(res, this.scale) * BigNum(1.internalCryptoBI, precision) } /** Performs this ** [exponent] */ @@ -108,12 +93,6 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable { return this.convertToScale(commonScale).int.compareTo(other.convertToScale(commonScale).int) } - /** Creates a [ClosedBigNumRange] between this and [that] */ - operator fun rangeTo(that: BigNum): ClosedBigNumRange = ClosedBigNumRange( - start = this, - endInclusive = that - ) - override fun hashCode(): Int = int.hashCode() + 3 * scale.hashCode() override fun equals(other: Any?): Boolean = (other is BigNum) && this.compareTo(other) == 0 @@ -148,15 +127,15 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable { fun toBigIntCeil(): BigInt { val it = this.toBigInt() val decimal = decimalPart - return if (decimal.isZero) it else (it + 1.bi) + return if (decimal.isZero) it else (it + 1.internalCryptoBI) } /** Converts this [BigInt] doing rounding when there are decimals */ fun toBigIntRound(): BigInt { - val firstDigit = decimalPart / 10.bi.pow(scale - 1) + val firstDigit = decimalPart / 10.internalCryptoBI.pow(scale - 1) return if (firstDigit.toInt() >= 5) toBigIntCeil() else toBigIntFloor() } /** Returns the decimal part as a [BigInt] of this BigNum so for `1.9123.bn` it will return `9123.bi` */ val decimalPart: BigInt - get() = int % 10.bi.pow(scale) + get() = int % 10.internalCryptoBI.pow(scale) } diff --git a/korlibs-crypto/src/korlibs/bignumber/BigRanges.kt b/korlibs-crypto/src/korlibs/bignumber/BigRanges.kt deleted file mode 100644 index ffcf0663df..0000000000 --- a/korlibs-crypto/src/korlibs/bignumber/BigRanges.kt +++ /dev/null @@ -1,167 +0,0 @@ -@file:Suppress("PackageDirectoryMismatch") - -package korlibs.bignumber.ranges - -import korlibs.bignumber.* - -/** - * Represents an inclusive range between two [BigNum] between [start]..[endInclusive]. - * - * @see kotlin.ranges.ClosedFloatRange - */ -class ClosedBigNumRange( - override val start: BigNum, - override val endInclusive: BigNum -) : ClosedRange { - - @Suppress("ConvertTwoComparisonsToRangeCheck") - override fun contains(value: BigNum): Boolean = value >= start && value <= endInclusive - - /** - * @see kotlin.ranges.ClosedFloatRange.isEmpty - */ - @Suppress("SimplifyNegatedBinaryExpression") - override fun isEmpty(): Boolean = !(start <= endInclusive) - - override fun equals(other: Any?): Boolean { - return other is ClosedBigNumRange && (isEmpty() && other.isEmpty() || - start == other.start && endInclusive == other.endInclusive) - } - - override fun hashCode(): Int { - return if (isEmpty()) -1 else 31 * start.hashCode() + endInclusive.hashCode() - } - - override fun toString(): String = "$start..$endInclusive" -} - - -/** - * Represents an inclusive range between two [BigInt] between [start]..[endInclusive]. - * - * @see kotlin.ranges.IntRange - */ -class BigIntRange( - start: BigInt, - endInclusive: BigInt -) : BigIntProgression(start, endInclusive, BigInt.ONE), ClosedRange { - override val start: BigInt get() = first - override val endInclusive: BigInt get() = last - - @Suppress("ConvertTwoComparisonsToRangeCheck") - override fun contains(value: BigInt): Boolean = first <= value && value <= last - - /** - * Checks whether the range is empty. - * - * The range is empty if its start value is greater than the end value. - */ - override fun isEmpty(): Boolean = first > last - - override fun equals(other: Any?): Boolean = - other is BigIntRange && (isEmpty() && other.isEmpty() || - first == other.first && last == other.last) - - override fun hashCode(): Int = - if (isEmpty()) -1 else (31 * first.toInt() + last.toInt()) - - override fun toString(): String = "$first..$last" - - companion object { - /** An empty range of values of type BigInt. */ - val EMPTY: IntRange = IntRange(1, 0) - } -} - -/** - * Represents an inclusive progression between two [BigInt] in the range [start]..[endInclusive] with a specific [step] - * - * @see kotlin.ranges.IntProgression - */ -open class BigIntProgression internal constructor( - start: BigInt, - endInclusive: BigInt, - val step: BigInt -) : Iterable { - init { - if (step == BigInt.ZERO) throw IllegalArgumentException("Step must be non-zero.") - } - - val first: BigInt = start - val last: BigInt = getProgressionLastElement(start, endInclusive, step) - - open fun isEmpty(): Boolean = if (step > BigInt.ZERO) first > last else first < last - - override fun iterator(): Iterator = BigIntProgressionIterator(first, last, step) - - override fun equals(other: Any?): Boolean = - other is BigIntProgression && (isEmpty() && other.isEmpty() || - first == other.first && last == other.last && step == other.step) - - override fun hashCode(): Int = - if (isEmpty()) -1 else (31 * (31 * first.toInt() + last.toInt()) + step.toInt()) - - override fun toString(): String = - if (step > BigInt.ZERO) "$first..$last step $step" else "$first downTo $last step ${-step}" - - /** - * @see IntProgression.step - */ - infix fun step(step: BigInt): BigIntProgression { - return fromClosedRange(first, last, if (this.step > BigInt.ZERO) step else -step) - } - - companion object { - fun fromClosedRange(rangeStart: BigInt, rangeEnd: BigInt, step: BigInt): BigIntProgression = - BigIntProgression(rangeStart, rangeEnd, step) - } -} - - -/** - * @see kotlin.ranges.IntProgressionIterator - */ -class BigIntProgressionIterator(first: BigInt, last: BigInt, val step: BigInt) : Iterator { - private val finalElement: BigInt = last - private var hasNext: Boolean = if (step > BigInt.ZERO) first <= last else first >= last - private var next: BigInt = if (hasNext) first else finalElement - - override fun hasNext(): Boolean = hasNext - - override fun next(): BigInt { - val value = next - if (value == finalElement) { - if (!hasNext) throw NoSuchElementException() - hasNext = false - } - else { - next += step - } - return value - } -} - - -/** - * @see kotlin.internal.mod - */ -private fun mod(a: BigInt, b: BigInt): BigInt { - val mod = a % b - return if (mod >= BigInt.ZERO) mod else mod + b -} - -/** - * @see kotlin.internal.differenceModulo - */ -private fun differenceModulo(a: BigInt, b: BigInt, c: BigInt): BigInt { - return mod(mod(a, c) - mod(b, c), c) -} - -/** - * @see kotlin.internal.getProgressionLastElement - */ -internal fun getProgressionLastElement(start: BigInt, end: BigInt, step: BigInt): BigInt = when { - step > BigInt.ZERO -> if (start >= end) end else end - differenceModulo(end, start, step) - step < BigInt.ZERO -> if (start <= end) end else end + differenceModulo(start, end, -step) - else -> throw IllegalArgumentException("Step is zero.") -} diff --git a/korlibs-crypto/src/korlibs/bignumber/CommonBigInt.kt b/korlibs-crypto/src/korlibs/bignumber/CommonBigInt.kt index b2498250c4..6e18773732 100644 --- a/korlibs-crypto/src/korlibs/bignumber/CommonBigInt.kt +++ b/korlibs-crypto/src/korlibs/bignumber/CommonBigInt.kt @@ -6,7 +6,7 @@ import kotlin.time.* /** * @TODO: Use JVM BigInteger and JS BigInt */ -class CommonBigInt private constructor(val data: UInt16ArrayZeroPad, override val signum: Int, var dummy: Boolean) : BigInt, BigIntConstructor by CommonBigInt { +internal class CommonBigInt private constructor(val data: UInt16ArrayZeroPad, override val signum: Int, var dummy: Boolean) : BigInt, BigIntConstructor by CommonBigInt { val isOne get() = isSmall && this == ONE val isSmall get() = data.size <= 1 val maxBits get() = data.size * CHUNK_BITS @@ -484,7 +484,7 @@ class CommonBigInt private constructor(val data: UInt16ArrayZeroPad, override va fun toBigNum(): BigNum = BigNum(this, 0) } -class UInt16ArrayZeroPad internal constructor(val data: IntArray) { +internal class UInt16ArrayZeroPad internal constructor(val data: IntArray) { val isAllZero: Boolean get() = data.all { it == 0 } val size get() = data.size diff --git a/korlibs-crypto/src/korlibs/crypto/Hasher.kt b/korlibs-crypto/src/korlibs/crypto/Hasher.kt index dfd5940757..969aeae8b7 100644 --- a/korlibs-crypto/src/korlibs/crypto/Hasher.kt +++ b/korlibs-crypto/src/korlibs/crypto/Hasher.kt @@ -2,12 +2,12 @@ package korlibs.crypto import korlibs.encoding.Base64 import korlibs.encoding.Hex -import korlibs.memory.arraycopy +import korlibs.memory.* import kotlin.math.min open class HasherFactory(val name: String, val create: () -> Hasher) { operator fun invoke(): Hasher = create() - fun digest(data: ByteArray) = create().also { it.update(data, 0, data.size) }.digest() + fun digest(data: ByteArray): Hash = create().also { it.update(data, 0, data.size) }.digest() inline fun digest(temp: ByteArray = ByteArray(0x1000), readBytes: (data: ByteArray) -> Int): Hash = this.create().also { diff --git a/korlibs-crypto/src/korlibs/math/Math.kt b/korlibs-crypto/src/korlibs/math/Math.kt index 4b72e4ec76..952dcebfed 100644 --- a/korlibs-crypto/src/korlibs/math/Math.kt +++ b/korlibs-crypto/src/korlibs/math/Math.kt @@ -2,14 +2,14 @@ package korlibs.math import kotlin.math.* -fun min(a: Int, b: Int, c: Int) = min(min(a, b), c) -fun min(a: Float, b: Float, c: Float) = min(min(a, b), c) -fun min(a: Double, b: Double, c: Double) = min(min(a, b), c) +internal fun min(a: Int, b: Int, c: Int) = min(min(a, b), c) +internal fun min(a: Float, b: Float, c: Float) = min(min(a, b), c) +internal fun min(a: Double, b: Double, c: Double) = min(min(a, b), c) -fun min(a: Int, b: Int, c: Int, d: Int) = min(min(min(a, b), c), d) -fun min(a: Float, b: Float, c: Float, d: Float) = min(min(min(a, b), c), d) -fun min(a: Double, b: Double, c: Double, d: Double) = min(min(min(a, b), c), d) +internal fun min(a: Int, b: Int, c: Int, d: Int) = min(min(min(a, b), c), d) +internal fun min(a: Float, b: Float, c: Float, d: Float) = min(min(min(a, b), c), d) +internal fun min(a: Double, b: Double, c: Double, d: Double) = min(min(min(a, b), c), d) -fun min(a: Int, b: Int, c: Int, d: Int, e: Int) = min(min(min(min(a, b), c), d), e) -fun min(a: Float, b: Float, c: Float, d: Float, e: Float) = min(min(min(min(a, b), c), d), e) -fun min(a: Double, b: Double, c: Double, d: Double, e: Double) = min(min(min(min(a, b), c), d), e) +internal fun min(a: Int, b: Int, c: Int, d: Int, e: Int) = min(min(min(min(a, b), c), d), e) +internal fun min(a: Float, b: Float, c: Float, d: Float, e: Float) = min(min(min(min(a, b), c), d), e) +internal fun min(a: Double, b: Double, c: Double, d: Double, e: Double) = min(min(min(min(a, b), c), d), e) diff --git a/korlibs-crypto/src/korlibs/memory/Arrays.kt b/korlibs-crypto/src/korlibs/memory/Arrays.kt index 022b300a0c..19b01f7943 100644 --- a/korlibs-crypto/src/korlibs/memory/Arrays.kt +++ b/korlibs-crypto/src/korlibs/memory/Arrays.kt @@ -1,64 +1,11 @@ package korlibs.memory /** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: Array, srcPos: Int, dst: Array, dstPos: Int, size: Int) { - src.copyInto(dst as Array, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: BooleanArray, srcPos: Int, dst: BooleanArray, dstPos: Int, size: Int) { - src.copyInto(dst, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: LongArray, srcPos: Int, dst: LongArray, dstPos: Int, size: Int) { - src.copyInto(dst, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: ByteArray, srcPos: Int, dst: ByteArray, dstPos: Int, size: Int) { - src.copyInto(dst, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: ShortArray, srcPos: Int, dst: ShortArray, dstPos: Int, size: Int) { - src.copyInto(dst, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: CharArray, srcPos: Int, dst: CharArray, dstPos: Int, size: Int) { - src.copyInto(dst, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: IntArray, srcPos: Int, dst: IntArray, dstPos: Int, size: Int) { - src.copyInto(dst, dstPos, srcPos, srcPos + size) -} - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: FloatArray, srcPos: Int, dst: FloatArray, dstPos: Int, size: Int) { +internal fun arraycopy(src: ByteArray, srcPos: Int, dst: ByteArray, dstPos: Int, size: Int) { src.copyInto(dst, dstPos, srcPos, srcPos + size) } /** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: DoubleArray, srcPos: Int, dst: DoubleArray, dstPos: Int, size: Int) { +internal fun arraycopy(src: IntArray, srcPos: Int, dst: IntArray, dstPos: Int, size: Int) { src.copyInto(dst, dstPos, srcPos, srcPos + size) } - -/** Copies [size] elements of [src] starting at [srcPos] into [dst] at [dstPos] */ -public fun arraycopy(src: List, srcPos: Int, dst: MutableList, dstPos: Int, size: Int) { - if (src === dst) error("Not supporting the same array") - for (n in 0 until size) { - dst[dstPos + n] = src[srcPos] - } -} - -public inline fun arraycopy(size: Int, src: Any?, srcPos: Int, dst: Any?, dstPos: Int, setDst: (Int, T) -> Unit, getSrc: (Int) -> T) { - val overlapping = src === dst && dstPos > srcPos - if (overlapping) { - var n = size - while (--n >= 0) setDst(dstPos + n, getSrc(srcPos + n)) - } else { - for (n in 0 until size) setDst(dstPos + n, getSrc(srcPos + n)) - } -} diff --git a/korlibs-crypto/src@darwin/korlibs/bignumber/BigInt.native.kt b/korlibs-crypto/src@darwin/korlibs/bignumber/BigInt.native.kt index 9685fecfd1..28982b9f8a 100644 --- a/korlibs-crypto/src@darwin/korlibs/bignumber/BigInt.native.kt +++ b/korlibs-crypto/src@darwin/korlibs/bignumber/BigInt.native.kt @@ -1,3 +1,3 @@ package korlibs.bignumber -actual val BigIntNativeFactory: BigIntConstructor = CommonBigInt +internal actual val BigIntNativeFactory: BigIntConstructor = CommonBigInt diff --git a/korlibs-crypto/src@js/korlibs/bignumber/BigInt.js.kt b/korlibs-crypto/src@js/korlibs/bignumber/BigInt.js.kt index 05c5819a42..6738bee669 100644 --- a/korlibs-crypto/src@js/korlibs/bignumber/BigInt.js.kt +++ b/korlibs-crypto/src@js/korlibs/bignumber/BigInt.js.kt @@ -1,24 +1,24 @@ package korlibs.bignumber -actual val BigIntNativeFactory: BigIntConstructor = object : BigIntConstructor { +internal actual val InternalCryptoBigIntNativeFactory: BigIntConstructor = object : BigIntConstructor { override fun create(value: Int): BigInt = - if (supportNativeJsBigInt) JsBigInt.create(value) else CommonBigInt.create(value) + if (supportNativeJsBigInt) InternalCryptoJsBigInt.create(value) else CommonBigInt.create(value) override fun create(value: String, radix: Int): BigInt = - if (supportNativeJsBigInt) JsBigInt.create(value, radix) else CommonBigInt.create(value, radix) + if (supportNativeJsBigInt) InternalCryptoJsBigInt.create(value, radix) else CommonBigInt.create(value, radix) } -class JsBigInt internal constructor(private val value: NativeJsBig) : BigInt, BigIntConstructor by JsBigInt { +internal class InternalCryptoJsBigInt internal constructor(private val value: NativeJsBig) : BigInt, BigIntConstructor by InternalCryptoJsBigInt { companion object : BigIntConstructor { - override fun create(value: Int): BigInt = JsBigInt(NativeJsBigInt(value)) + override fun create(value: Int): BigInt = InternalCryptoJsBigInt(NativeJsBigInt(value)) override fun create(value: String, radix: Int): BigInt { if (value.isEmpty()) { throw BigIntInvalidFormatException("Zero length BigInteger") } if (radix == 10) { validateRadix(value, radix) - return JsBigInt(NativeJsBigInt(value)) + return InternalCryptoJsBigInt(NativeJsBigInt(value)) } return super.create(value, radix) } @@ -27,7 +27,7 @@ class JsBigInt internal constructor(private val value: NativeJsBig) : BigInt, Bi } } - val BigInt.js: dynamic get() = (this as JsBigInt).value.asDynamic() + val BigInt.js: dynamic get() = (this as InternalCryptoJsBigInt).value.asDynamic() val Int.js: dynamic get() = NativeJsBigInt(this) override val signum: Int get() { @@ -36,33 +36,33 @@ class JsBigInt internal constructor(private val value: NativeJsBig) : BigInt, Bi return 0 } - override fun unaryMinus(): BigInt = JsBigInt(-js) + override fun unaryMinus(): BigInt = InternalCryptoJsBigInt(-js) - override fun inv(): BigInt = JsBigInt(NativeJsInv(js)) + override fun inv(): BigInt = InternalCryptoJsBigInt(NativeJsInv(js)) override fun pow(exponent: BigInt): BigInt { if (exponent.isNegative) throw BigIntNegativeExponentException() - return JsBigInt(NativeJsPow(js, exponent.js)) + return InternalCryptoJsBigInt(NativeJsPow(js, exponent.js)) } override fun pow(exponent: Int): BigInt { if (exponent < 0) throw BigIntNegativeExponentException() - return pow(JsBigInt(NativeJsBigInt(exponent))) + return pow(InternalCryptoJsBigInt(NativeJsBigInt(exponent))) } - override fun and(other: BigInt): BigInt = JsBigInt(NativeJsAnd(js, other.js)) - override fun or(other: BigInt): BigInt = JsBigInt(NativeJsOr(js, other.js)) - override fun xor(other: BigInt): BigInt = JsBigInt(NativeJsXor(js, other.js)) + override fun and(other: BigInt): BigInt = InternalCryptoJsBigInt(NativeJsAnd(js, other.js)) + override fun or(other: BigInt): BigInt = InternalCryptoJsBigInt(NativeJsOr(js, other.js)) + override fun xor(other: BigInt): BigInt = InternalCryptoJsBigInt(NativeJsXor(js, other.js)) - override fun shl(count: Int): BigInt = JsBigInt(NativeJsShl(js, count.js)) - override fun shr(count: Int): BigInt = JsBigInt(NativeJsShr(js, count.js)) + override fun shl(count: Int): BigInt = InternalCryptoJsBigInt(NativeJsShl(js, count.js)) + override fun shr(count: Int): BigInt = InternalCryptoJsBigInt(NativeJsShr(js, count.js)) - override fun plus(other: BigInt): BigInt = JsBigInt(this.js + other.js) - override fun minus(other: BigInt): BigInt = JsBigInt(this.js - other.js) - override fun times(other: BigInt): BigInt = JsBigInt(this.js * other.js) + override fun plus(other: BigInt): BigInt = InternalCryptoJsBigInt(this.js + other.js) + override fun minus(other: BigInt): BigInt = InternalCryptoJsBigInt(this.js - other.js) + override fun times(other: BigInt): BigInt = InternalCryptoJsBigInt(this.js * other.js) override fun div(other: BigInt): BigInt { if (other.isZero) throw BigIntDivisionByZeroException() - return JsBigInt(this.js / other.js) + return InternalCryptoJsBigInt(this.js / other.js) } - override fun rem(other: BigInt): BigInt = JsBigInt(this.js % other.js) + override fun rem(other: BigInt): BigInt = InternalCryptoJsBigInt(this.js % other.js) private val cachedToString by lazy { value.toString() } @@ -77,7 +77,7 @@ class JsBigInt internal constructor(private val value: NativeJsBig) : BigInt, Bi } override fun hashCode(): Int = cachedToString.hashCode() - override fun equals(other: Any?): Boolean = other is JsBigInt && this.value == other.value + override fun equals(other: Any?): Boolean = other is InternalCryptoJsBigInt && this.value == other.value } @JsName("BigInt") diff --git a/korlibs-crypto/src@jvmAndroid/korlibs/bignumber/BigInt.jvm.kt b/korlibs-crypto/src@jvmAndroid/korlibs/bignumber/BigInt.jvm.kt index b9fc1fea44..f005c42e77 100644 --- a/korlibs-crypto/src@jvmAndroid/korlibs/bignumber/BigInt.jvm.kt +++ b/korlibs-crypto/src@jvmAndroid/korlibs/bignumber/BigInt.jvm.kt @@ -3,17 +3,17 @@ package korlibs.bignumber import java.math.* /** Converts a [BigInteger] into a [BigInt] ([JvmBigInt]) */ -val BigInteger.bi: JvmBigInt get() = JvmBigInt(this) +internal val BigInteger.bi: JvmBigInt get() = JvmBigInt(this) /** Converts a [BigInt] into a [BigInteger] */ -fun BigInt.toBigInteger(): BigInteger = when (this) { +internal fun BigInt.toBigInteger(): BigInteger = when (this) { is JvmBigInt -> this.value else -> BigInteger(this.toString()) } -actual val BigIntNativeFactory: BigIntConstructor = JvmBigInt +internal actual val InternalCryptoBigIntNativeFactory: BigIntConstructor = JvmBigInt -class JvmBigInt(val value: BigInteger) : BigInt, BigIntConstructor by JvmBigInt { +internal class JvmBigInt(val value: BigInteger) : BigInt, BigIntConstructor by JvmBigInt { constructor(value: Int) : this(BigInteger.valueOf(value.toLong())) constructor(value: Long) : this(BigInteger.valueOf(value)) constructor(value: String, radix: Int) : this(try { diff --git a/korlibs-crypto/src@wasmJs/korlibs/bignumber/BigInt.wasm.kt b/korlibs-crypto/src@wasmJs/korlibs/bignumber/BigInt.wasm.kt index 9685fecfd1..f7741ff324 100644 --- a/korlibs-crypto/src@wasmJs/korlibs/bignumber/BigInt.wasm.kt +++ b/korlibs-crypto/src@wasmJs/korlibs/bignumber/BigInt.wasm.kt @@ -1,3 +1,3 @@ package korlibs.bignumber -actual val BigIntNativeFactory: BigIntConstructor = CommonBigInt +internal actual val InternalCryptoBigIntNativeFactory: BigIntConstructor = CommonBigInt