From 37b2cbfedd5f8f93a7b5c4430ad59195f1bfca45 Mon Sep 17 00:00:00 2001 From: tursom Date: Tue, 3 Nov 2020 08:53:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=B7=BB=E5=8A=A0=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E5=88=86=E7=BB=84=E5=8A=A0=E5=AF=86=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/tursom/core/datastruct/AtomicBitSet.kt | 73 +++-- .../core/encrypt/AbstractPublicKeyEncrypt.kt | 266 ++++++++++++++---- .../encrypt/BlockCipherModeOfOperation.kt | 5 + .../kotlin/cn/tursom/core/encrypt/Encrypt.kt | 7 + src/main/kotlin/cn/tursom/core/encrypt/RSA.kt | 47 +++- 5 files changed, 313 insertions(+), 85 deletions(-) create mode 100644 src/main/kotlin/cn/tursom/core/encrypt/BlockCipherModeOfOperation.kt diff --git a/src/main/kotlin/cn/tursom/core/datastruct/AtomicBitSet.kt b/src/main/kotlin/cn/tursom/core/datastruct/AtomicBitSet.kt index 26e1d09..b3a2307 100644 --- a/src/main/kotlin/cn/tursom/core/datastruct/AtomicBitSet.kt +++ b/src/main/kotlin/cn/tursom/core/datastruct/AtomicBitSet.kt @@ -1,7 +1,10 @@ package cn.tursom.core.datastruct +import cn.tursom.core.randomInt +import cn.tursom.core.usingTime import java.io.Serializable import java.lang.reflect.Field +import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicLongArray import kotlin.random.Random @@ -26,6 +29,7 @@ class AtomicBitSet(beginSize: Long = 256, val defaultState: Boolean = false) : S bitSet.array.forEach { count += it.bitCount } return count } + val upCount get() = trueCount init { val default = if (defaultState) -1L else 0L @@ -83,7 +87,33 @@ class AtomicBitSet(beginSize: Long = 256, val defaultState: Boolean = false) : S } fun firstUp(): Long { - bitSet.forEachIndexed { index, l -> + return scanUp(0, bitSet.length()) + } + + fun randomUpIndex(): Long { + val startIndex = Random.nextInt(bitSet.length()) + var scan = scanUp(startIndex, bitSet.length() - startIndex) + if (scan >= 0) return scan + scan = scanUp(startIndex - 1, startIndex, false) + if (scan >= 0) return scan + return -1 + } + + fun firstDown(): Long { + return scanDown(0, bitSet.length()) + } + + fun getDownIndex(): Long { + val startIndex = Random.nextInt(bitSet.length()) + var scan = scanDown(startIndex, bitSet.length() - startIndex) + if (scan >= 0) return scan + scan = scanDown(startIndex - 1, startIndex, false) + if (scan >= 0) return scan + return -1 + } + + private fun scanUp(fromIndex: Int, length: Int, asc: Boolean = true): Long { + bitSet.forEachIndexed(fromIndex, length, asc) { index, l -> if (l != 0L) { for (i in 0 until 8) { if (l and scanArray[i] != 0L) { @@ -98,19 +128,6 @@ class AtomicBitSet(beginSize: Long = 256, val defaultState: Boolean = false) : S return -1 } - fun firstDown(): Long { - return scanDown(0, bitSet.length()) - } - - fun getDownIndex(): Long { - val startIndex = Random.nextInt(0, bitSet.length()) - var scan = scanDown(startIndex, bitSet.length() - startIndex) - if (scan >= 0) return scan - scan = scanDown(startIndex - 1, startIndex, false) - if (scan >= 0) return scan - return -1 - } - private fun scanDown(fromIndex: Int, length: Int, asc: Boolean = true): Long { bitSet.forEachIndexed(fromIndex, length, asc) { index, l -> if (l != -1L) { @@ -193,21 +210,45 @@ class AtomicBitSet(beginSize: Long = 256, val defaultState: Boolean = false) : S array.isAccessible = true } - inline fun AtomicLongArray.forEachIndexed(action: (index: Int, Long) -> Unit) { + private inline fun AtomicLongArray.forEachIndexed(action: (index: Int, Long) -> Unit) { repeat(length()) { action(it, get(it)) } } - inline fun AtomicLongArray.forEachIndexed(startIndex: Int, length: Int = length(), asc: Boolean = true, action: (index: Int, Long) -> Unit) { + private inline fun AtomicLongArray.forEachIndexed(startIndex: Int, length: Int = length(), asc: Boolean = true, action: (index: Int, Long) -> Unit) { repeat(length) { val index = if (asc) { startIndex + it } else { startIndex - it } + //scand.incrementAndGet() action(index, get(index)) } } } } + +//val scand = AtomicInteger(0) + +fun main() { + val size = 1000000 + val bitSet = AtomicBitSet(size.toLong()) + println(usingTime { + repeat(1000) { + bitSet.downAll() + repeat(size) { + val index = bitSet.getDownIndex() + bitSet.up(index) + repeat(randomInt(0, 3) / 2) { + val randomUpIndex = bitSet.randomUpIndex() + if (randomUpIndex >= 0) { + bitSet.down(randomUpIndex) + } + } + } + } + }) + //println(scand.get() / 100) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/encrypt/AbstractPublicKeyEncrypt.kt b/src/main/kotlin/cn/tursom/core/encrypt/AbstractPublicKeyEncrypt.kt index e9844f5..0bb9244 100644 --- a/src/main/kotlin/cn/tursom/core/encrypt/AbstractPublicKeyEncrypt.kt +++ b/src/main/kotlin/cn/tursom/core/encrypt/AbstractPublicKeyEncrypt.kt @@ -1,14 +1,21 @@ package cn.tursom.core.encrypt +import cn.tursom.core.toHexString +import cn.tursom.core.toUTF8String import java.security.* +import java.security.interfaces.RSAPublicKey import java.security.spec.X509EncodedKeySpec import javax.crypto.Cipher +import kotlin.experimental.xor +import kotlin.math.min +import kotlin.random.Random @Suppress("unused", "MemberVisibilityCanBePrivate") abstract class AbstractPublicKeyEncrypt( val algorithm: String, final override val publicKey: PublicKey, - final override val privateKey: PrivateKey? = null + final override val privateKey: PrivateKey? = null, + val modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, ) : PublicKeyEncrypt { val publicKeyEncoded get() = publicKey.encoded!! val privateKeyEncoded get() = privateKey?.encoded @@ -39,67 +46,56 @@ abstract class AbstractPublicKeyEncrypt( override fun signature(digest: String): String = this@AbstractPublicKeyEncrypt.signature(digest) } - constructor(algorithm: String, keyPair: KeyPair) : this(algorithm, keyPair.public as PublicKey, keyPair.private as PrivateKey) - - constructor(algorithm: String, keySize: Int = 1024) : this(algorithm, KeyPairGenerator.getInstance(algorithm).let { - it.initialize(keySize) - it.generateKeyPair() - }) - - constructor(algorithm: String, publicKey: ByteArray) : this(algorithm, KeyFactory.getInstance(algorithm).generatePublic(X509EncodedKeySpec(publicKey)) as PublicKey) - - override fun encrypt(data: ByteArray, offset: Int, size: Int): ByteArray { - return if (size < encryptMaxLen) { - encryptCipher.doFinal(data, offset, size) - } else { - val buffer = ByteArray(((size - 1) / encryptMaxLen + 1) * decryptMaxLen) - buffer.copyOf(doFinal(data, offset, size, buffer, encryptCipher, encryptMaxLen)) - } + private val blockCipher: Encrypt = when (modeOfOperation) { + BlockCipherModeOfOperation.ECB -> ECBBlockCipher() + BlockCipherModeOfOperation.CBC -> CBCBlockCipher() + else -> TODO() } - override fun decrypt(data: ByteArray, offset: Int, size: Int): ByteArray { - return if (data.size < decryptMaxLen) { - decryptCipher.doFinal(data, offset, size) - } else { - val buffer = ByteArray(size / decryptMaxLen * encryptMaxLen + 11) - buffer.copyOf(doFinal(data, offset, size, buffer, decryptCipher, decryptMaxLen)) + override var encryptInitVector: ByteArray? + get() = blockCipher.encryptInitVector + set(value) { + blockCipher.encryptInitVector = value + } + override var decryptInitVector: ByteArray? + get() = blockCipher.decryptInitVector + set(value) { + blockCipher.decryptInitVector = value } - } - override fun encrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int { - return if (data.size < decryptMaxLen) { - encryptCipher.doFinal(data, offset, size, buffer, bufferOffset) - } else { - doFinal(data, offset, size, buffer, encryptCipher, decryptMaxLen, bufferOffset) - } - } + constructor( + algorithm: String, + keyPair: KeyPair, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, + ) : this(algorithm, keyPair.public as PublicKey, keyPair.private as PrivateKey, modeOfOperation = modeOfOperation) - override fun decrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int { - return if (data.size < decryptMaxLen) { - decryptCipher.doFinal(data, offset, size, buffer, bufferOffset) - } else { - doFinal(data, offset, size, buffer, decryptCipher, decryptMaxLen, bufferOffset) - } - } + constructor( + algorithm: String, + keySize: Int = 1024, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, + ) : this( + algorithm, + KeyPairGenerator.getInstance(algorithm).let { + it.initialize(keySize) + it.generateKeyPair() + }, + modeOfOperation = modeOfOperation + ) - private fun doFinal( - data: ByteArray, - offset: Int, - size: Int, - buffer: ByteArray, - cipher: Cipher, - blockSize: Int, - bufferOffset: Int = 0 - ): Int { - var readPosition = offset - var writeIndex = bufferOffset - while (readPosition + blockSize < size) { - writeIndex += cipher.doFinal(data, readPosition, blockSize, buffer, writeIndex) - readPosition += blockSize - } - writeIndex += cipher.doFinal(data, readPosition, size - readPosition, buffer, writeIndex) - return writeIndex - bufferOffset - } + constructor( + algorithm: String, + publicKey: ByteArray, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, + ) : this( + algorithm, + KeyFactory.getInstance(algorithm).generatePublic(X509EncodedKeySpec(publicKey)) as PublicKey, + modeOfOperation = modeOfOperation + ) + + override fun encrypt(data: ByteArray, offset: Int, size: Int): ByteArray = blockCipher.encrypt(data, offset, size) + override fun decrypt(data: ByteArray, offset: Int, size: Int): ByteArray = blockCipher.decrypt(data, offset, size) + override fun encrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int = blockCipher.encrypt(data, buffer, bufferOffset, offset, size) + override fun decrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int = blockCipher.decrypt(data, buffer, bufferOffset, offset, size) protected open fun signature(digest: String) = "${digest}with$algorithm" @@ -134,4 +130,162 @@ abstract class AbstractPublicKeyEncrypt( result = 31 * result + (privateKey?.hashCode() ?: 0) return result } + + protected inner class ECBBlockCipher : Encrypt { + override fun encrypt(data: ByteArray, offset: Int, size: Int): ByteArray { + return if (size < encryptMaxLen) { + encryptCipher.doFinal(data, offset, size) + } else { + val buffer = ByteArray(((size - 1) / encryptMaxLen + 1) * decryptMaxLen) + buffer.copyOf(doFinal(data, offset, size, buffer, encryptCipher, encryptMaxLen)) + } + } + + override fun decrypt(data: ByteArray, offset: Int, size: Int): ByteArray { + return if (data.size < decryptMaxLen) { + decryptCipher.doFinal(data, offset, size) + } else { + val buffer = ByteArray(size / decryptMaxLen * encryptMaxLen + 11) + buffer.copyOf(doFinal(data, offset, size, buffer, decryptCipher, decryptMaxLen)) + } + } + + override fun encrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int { + return if (data.size < decryptMaxLen) { + encryptCipher.doFinal(data, offset, size, buffer, bufferOffset) + } else { + doFinal(data, offset, size, buffer, encryptCipher, decryptMaxLen, bufferOffset) + } + } + + override fun decrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int { + return if (data.size < decryptMaxLen) { + decryptCipher.doFinal(data, offset, size, buffer, bufferOffset) + } else { + doFinal(data, offset, size, buffer, decryptCipher, decryptMaxLen, bufferOffset) + } + } + + private fun doFinal( + data: ByteArray, + offset: Int, + size: Int, + buffer: ByteArray, + cipher: Cipher, + blockSize: Int, + bufferOffset: Int = 0, + ): Int { + var readPosition = offset + var writeIndex = bufferOffset + while (readPosition + blockSize < size) { + writeIndex += cipher.doFinal(data, readPosition, blockSize, buffer, writeIndex) + readPosition += blockSize + } + writeIndex += cipher.doFinal(data, readPosition, size - readPosition, buffer, writeIndex) + return writeIndex - bufferOffset + } + } + + protected inner class CBCBlockCipher : Encrypt { + override var encryptInitVector: ByteArray? = Random.nextBytes(encryptMaxLen) + set(value) { + value ?: return + field = value + encBuf = value + } + override var decryptInitVector: ByteArray? = null + set(value) { + field = value + decBuf = value + } + + private var encBuf = encryptInitVector!! + private var decBuf: ByteArray? = decryptInitVector + + override fun encrypt(data: ByteArray, offset: Int, size: Int): ByteArray { + val buffer = ByteArray(((size - 1) / encryptMaxLen + 1) * decryptMaxLen) + //return buffer.copyOf(encrypt(data, buffer, 0, offset, size)) + encrypt(data, buffer, 0, offset, size) + return buffer + } + + override fun encrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int { + var end = offset + var start: Int + var writeIndex = bufferOffset + do { + start = end + end += encryptMaxLen + end = min(data.size, end) + (0 until end - start).forEach { index -> + encBuf[index] = encBuf[index] xor data[start + index] + } + writeIndex += encryptCipher.doFinal(encBuf, 0, encBuf.size, buffer, writeIndex) + //println("${data.size} $start->$end $writeIndex") + } while (end < offset + size) + return writeIndex - bufferOffset + } + + override fun decrypt(data: ByteArray, offset: Int, size: Int): ByteArray { + val decryptInitVector = decBuf!! + var start: Int + var end = offset + val buffer = ByteArray(((size - 1) / decryptMaxLen + 1) * encryptMaxLen + 11) + var writeIndex = 0 + do { + start = end + end += decryptMaxLen + end = min(data.size, end) + println("${data.size}, $start->$end, ${buffer.size}, $writeIndex") + val writeIndexBefore = writeIndex + writeIndex += decryptCipher.doFinal(data, start, end - start, buffer, writeIndex) + if (start == 0) { + repeat(encryptMaxLen) { + buffer[it] = buffer[it] xor decryptInitVector[it] + } + } else { + repeat(writeIndex - writeIndexBefore) { + buffer[writeIndexBefore + it] = buffer[writeIndexBefore + it] xor data[start + it] + } + } + } while (end < offset + size) + decBuf = buffer.copyOfRange(buffer.size - encryptMaxLen, buffer.size) + return buffer.copyOf(writeIndex) + } + + override fun decrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int): Int { + TODO("Not yet implemented") + } + + //private fun doFinal(data: ByteArray, buffer: ByteArray, bufferOffset: Int, offset: Int, size: Int, cipher: Cipher): Int { + // var start = offset + // var end = offset + // var writeIndex = bufferOffset + // do { + // end += decryptMaxLen + // end = min(data.size, end) + // encBuf.indices.forEach { index -> + // encBuf[index] = encBuf[index] xor data[start + index] + // } + // writeIndex += cipher.doFinal(encBuf, 0, encBuf.size, buffer, writeIndex) + // start += decryptMaxLen + // } while (end < offset + size) + // return writeIndex - bufferOffset + //} + } + + companion object { + private val random = Random(System.currentTimeMillis()) + } +} + + +fun main() { + val source = "HelloWorld".repeat(100).toByteArray() + val rsa = RSA() + val decodeRsa = rsa.public + decodeRsa.decryptInitVector = rsa.encryptInitVector + val encrypt = rsa.encrypt(source) + //println(encrypt.toHexString()) + println(decodeRsa.decrypt(encrypt).toUTF8String()) } \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/encrypt/BlockCipherModeOfOperation.kt b/src/main/kotlin/cn/tursom/core/encrypt/BlockCipherModeOfOperation.kt new file mode 100644 index 0000000..d1925fa --- /dev/null +++ b/src/main/kotlin/cn/tursom/core/encrypt/BlockCipherModeOfOperation.kt @@ -0,0 +1,5 @@ +package cn.tursom.core.encrypt + +enum class BlockCipherModeOfOperation { + ECB, CBC, CFB, OFB, CTR, +} \ No newline at end of file diff --git a/src/main/kotlin/cn/tursom/core/encrypt/Encrypt.kt b/src/main/kotlin/cn/tursom/core/encrypt/Encrypt.kt index c36e53e..5c24efe 100644 --- a/src/main/kotlin/cn/tursom/core/encrypt/Encrypt.kt +++ b/src/main/kotlin/cn/tursom/core/encrypt/Encrypt.kt @@ -3,6 +3,13 @@ package cn.tursom.core.encrypt import cn.tursom.core.buffer.ByteBuffer interface Encrypt { + var encryptInitVector: ByteArray? + get() = null + set(_) {} + var decryptInitVector: ByteArray? + get() = null + set(_) {} + fun encrypt(data: ByteArray, offset: Int = 0, size: Int = data.size - offset): ByteArray fun decrypt(data: ByteArray, offset: Int = 0, size: Int = data.size - offset): ByteArray fun encrypt(data: ByteArray, buffer: ByteArray, bufferOffset: Int = 0, offset: Int = 0, size: Int = data.size - offset): Int diff --git a/src/main/kotlin/cn/tursom/core/encrypt/RSA.kt b/src/main/kotlin/cn/tursom/core/encrypt/RSA.kt index ca9d7e5..cc13f15 100644 --- a/src/main/kotlin/cn/tursom/core/encrypt/RSA.kt +++ b/src/main/kotlin/cn/tursom/core/encrypt/RSA.kt @@ -10,28 +10,49 @@ import java.security.spec.X509EncodedKeySpec @Suppress("unused", "MemberVisibilityCanBePrivate") class RSA( publicKey: RSAPublicKey, - privateKey: RSAPrivateKey? = null -) : AbstractPublicKeyEncrypt("RSA", publicKey, privateKey) { + privateKey: RSAPrivateKey? = null, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, +) : AbstractPublicKeyEncrypt("RSA", publicKey, privateKey, modeOfOperation = modeOfOperation) { - val keySize = publicKey.modulus.bitLength() - override val decryptMaxLen = keySize / 8 - override val encryptMaxLen = decryptMaxLen - 11 + val keySize get() = (publicKey as RSAPublicKey).modulus.bitLength() + override val decryptMaxLen get() = keySize / 8 + override val encryptMaxLen get() = decryptMaxLen - 11 - override val public by lazy { + override val public by lazy { if (privateKey == null) { this } else { - RSA(publicKey) + RSA(publicKey, modeOfOperation = modeOfOperation) } } - constructor(keyPair: KeyPair) : this(keyPair.public as RSAPublicKey, keyPair.private as RSAPrivateKey) + constructor( + keyPair: KeyPair, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, + ) : this( + keyPair.public as RSAPublicKey, + keyPair.private as RSAPrivateKey, + modeOfOperation + ) - constructor(keySize: Int = 1024) : this(KeyPairGenerator.getInstance("RSA").let { - it.initialize(keySize) - it.generateKeyPair() - }) + constructor( + keySize: Int = 1024, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, + ) : this( + KeyPairGenerator.getInstance("RSA").let { + it.initialize(keySize) + it.generateKeyPair() + }, + modeOfOperation + ) - constructor(publicKey: ByteArray) : this(KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(publicKey)) as RSAPublicKey) + constructor( + publicKey: ByteArray, + modeOfOperation: BlockCipherModeOfOperation = BlockCipherModeOfOperation.ECB, + ) : this( + KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(publicKey)) as RSAPublicKey, + null, + modeOfOperation + ) }