diff --git a/app/src/main/kotlin/me/leon/Digests.kt b/app/src/main/kotlin/me/leon/Digests.kt index 1206a9f5c0..35783f8e0d 100644 --- a/app/src/main/kotlin/me/leon/Digests.kt +++ b/app/src/main/kotlin/me/leon/Digests.kt @@ -52,6 +52,7 @@ val ALGOS_HASH = "DSTU7564" to listOf("256", "384", "512"), "Skein" to listOf( + "256-128", "256-160", "256-224", "256-256", diff --git a/app/src/main/kotlin/me/leon/ext/crypto/AsymmetircCrypto.kt b/app/src/main/kotlin/me/leon/ext/crypto/AsymmetircCrypto.kt index 32feb5690a..c48dea9b08 100644 --- a/app/src/main/kotlin/me/leon/ext/crypto/AsymmetircCrypto.kt +++ b/app/src/main/kotlin/me/leon/ext/crypto/AsymmetircCrypto.kt @@ -19,6 +19,28 @@ import org.bouncycastle.pqc.crypto.lms.LMSigParameters import org.bouncycastle.pqc.jcajce.spec.LMSKeyGenParameterSpec import org.bouncycastle.pqc.jcajce.spec.SPHINCSPlusParameterSpec +val ASYMMETRIC_ALGOS = mapOf( + "RSA" to listOf(512, 1024, 2048, 3072, 4096), + "ElGamal" to listOf(512, 1024, 2048), + "SM2" to listOf(256), +) + +val RSA_PADDINGS = listOf( + "PKCS1Padding", + "NoPadding", + "OAEPWithMD5AndMGF1Padding", + "OAEPWithSHA1AndMGF1Padding", + "OAEPWithSHA224AndMGF1Padding", + "OAEPWithSHA256AndMGF1Padding", + "OAEPWithSHA384AndMGF1Padding", + "OAEPWithSHA512AndMGF1Padding", + "OAEPWithSHA3-224AndMGF1Padding", + "OAEPWithSHA3-256AndMGF1Padding", + "OAEPWithSHA3-384AndMGF1Padding", + "OAEPWithSHA3-512AndMGF1Padding", + "ISO9796-1Padding", +) + fun String.removePemInfo() = replace("---+(?:END|BEGIN) (?:RSA )?\\w+ KEY---+|\n|\r|\r\n".toRegex(), "") @@ -114,7 +136,7 @@ fun ByteArray.privateDecrypt( alg: String, ): ByteArray = asymmetricDecrypt(key.toPrivateKey(alg), alg) -fun ByteArray.asymmtricEncrypt(key: Key?, alg: String, reserved: Int = 11): ByteArray = +fun ByteArray.asymmetricEncrypt(key: Key?, alg: String, reserved: Int = 11): ByteArray = Cipher.getInstance(alg).run { init(Cipher.ENCRYPT_MODE, key) val bitLen = @@ -136,7 +158,7 @@ fun ByteArray.asymmtricEncrypt(key: Key?, alg: String, reserved: Int = 11): Byte } fun ByteArray.privateEncrypt(key: String, alg: String, reserved: Int = 11): ByteArray = - asymmtricEncrypt(key.toPrivateKey(alg), alg, reserved) + asymmetricEncrypt(key.toPrivateKey(alg), alg, reserved) fun PublicKey.bitLength() = (this as? RSAPublicKey)?.modulus?.bitLength() ?: 1024 @@ -144,7 +166,7 @@ fun PrivateKey.bitLength() = (this as? RSAPrivateKey)?.modulus?.bitLength() ?: 1 /** 生成密钥对 private key pkcs8 */ fun genKeys(alg: String, keySize: Int) = - KeyPairGenerator.getInstance(alg).run { + KeyPairGenerator.getInstance(if (alg.contains("/")) alg.substringBefore('/') else alg).run { initialize(keySize) val keyPair = generateKeyPair() val publicKey = keyPair.public @@ -152,14 +174,11 @@ fun genKeys(alg: String, keySize: Int) = arrayOf(publicKey.encoded.base64(), privateKey.encoded.base64()) } -val ASYMMETRIC_ALG = - mapOf( - "RSA" to listOf(512, 1024, 2048, 3072, 4096), - "SM2" to listOf(256), - "ElGamal" to listOf(512, 1024, 2048) - ) - -private fun String.properKeyPairAlg() = takeUnless { it.equals("SM2", true) } ?: "EC" +private fun String.properKeyPairAlg() = when { + this == "SM2" -> "EC" + this.startsWith("RSA") -> "RSA" + else -> this +} private val ecGenParameterSpec = mapOf( @@ -211,7 +230,7 @@ fun genKeys(alg: String, params: List = emptyList()) = fun checkKeyPair(pub: String, pri: String, alg: String = "RSA"): Boolean { val testData = byteArrayOf(67) - return testData.asymmtricEncrypt(pub.toPublicKey(alg), alg).run { + return testData.asymmetricEncrypt(pub.toPublicKey(alg), alg).run { asymmetricDecrypt(pri.toPrivateKey(alg), alg).contentEquals(testData) } } @@ -225,9 +244,9 @@ fun pkcs8ToPkcs1(pkcs8: String) = fun pkcs1ToPkcs8(pkcs1: String) = PrivateKeyInfo( - AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption), - ASN1Primitive.fromByteArray(pkcs1.base64Decode()) - ) + AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption), + ASN1Primitive.fromByteArray(pkcs1.base64Decode()) + ) .encoded .run { PKCS8EncodedKeySpec(this).run { diff --git a/app/src/main/kotlin/me/leon/ext/crypto/MACs.kt b/app/src/main/kotlin/me/leon/ext/crypto/MACs.kt index 3f5f984847..f56c786319 100644 --- a/app/src/main/kotlin/me/leon/ext/crypto/MACs.kt +++ b/app/src/main/kotlin/me/leon/ext/crypto/MACs.kt @@ -26,6 +26,7 @@ object MACs { "HmacDSTU7564" to listOf("256", "384", "512"), "HmacSkein" to listOf( + "256-128", "256-160", "256-224", "256-256", diff --git a/app/src/main/kotlin/me/leon/view/AsymmetricCryptoView.kt b/app/src/main/kotlin/me/leon/view/AsymmetricCryptoView.kt index 974be93dca..b9c987be9c 100644 --- a/app/src/main/kotlin/me/leon/view/AsymmetricCryptoView.kt +++ b/app/src/main/kotlin/me/leon/view/AsymmetricCryptoView.kt @@ -16,7 +16,9 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { private val isSingleLine = SimpleBooleanProperty(false) private val privateKeyEncrypt = SimpleBooleanProperty(false) private val isProcessing = SimpleBooleanProperty(false) - private var cbBits :ComboBox by singleAssign() + private val isEnablePadding = SimpleBooleanProperty(true) + + private var cbBits: ComboBox by singleAssign() lateinit var taInput: TextArea lateinit var taKey: TextArea lateinit var taOutput: TextArea @@ -38,6 +40,7 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { if (privateKeyEncrypt.get()) "private key encrypt" else "public key encrypt" } cost: $timeConsumption ms" + private val selectedPadding = SimpleStringProperty(RSA_PADDINGS.first()) private lateinit var labelInfo: Label private var keyText: String get() = @@ -51,22 +54,19 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { } private val alg - get() = selectedAlg.get() + get() = with(selectedAlg.get()) { + if (this == "RSA") "$this/NONE/${selectedPadding.get()}" + else this + } private var isEncrypt = true private var inputEncode = "raw" private var outputEncode = "base64" private lateinit var tgInput: ToggleGroup private lateinit var tgOutput: ToggleGroup - private val algoMaps = mapOf( - "RSA" to listOf(512, 1024, 2048, 3072, 4096), - "ElGamal" to listOf(512, 1024, 2048), - "SM2" to listOf(256), - ) - private val bitsLists = mutableListOf(512, 1024, 2048, 3072, 4096) - private val algs = algoMaps.keys.toMutableList() + private val algs = ASYMMETRIC_ALGOS.keys.toMutableList() private val selectedAlg = SimpleStringProperty(algs.first()) - private val selectedBits = SimpleIntegerProperty(algoMaps[selectedAlg.get()]!!.first()) + private val selectedBits = SimpleIntegerProperty(ASYMMETRIC_ALGOS[selectedAlg.get()]!!.first()) private val isPrivateKey get() = isEncrypt && privateKeyEncrypt.get() || !isEncrypt && !privateKeyEncrypt.get() @@ -89,12 +89,12 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { private fun updateKeySize() { runAsync { runCatching { - if (isPrivateKey) { - controller.lengthFromPri(keyText) - } else { - controller.lengthFromPub(keyText) - } + if (isPrivateKey) { + controller.lengthFromPri(keyText) + } else { + controller.lengthFromPub(keyText) } + } .getOrDefault(1024) } ui { selectedBits.set(it) } } @@ -159,13 +159,22 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { combobox(selectedAlg, algs) { cellFormat { text = it.toString() } } selectedAlg.addListener { _, _, newValue -> newValue?.run { - cbBits.items = algoMaps[newValue]!!.asObservable() - selectedBits.set(algoMaps[newValue]!!.first()) - cbBits.isDisable = algoMaps[newValue]!!.size == 1 + cbBits.items = ASYMMETRIC_ALGOS[newValue]!!.asObservable() + selectedBits.set(ASYMMETRIC_ALGOS[newValue]!!.first()) + cbBits.isDisable = ASYMMETRIC_ALGOS[newValue]!!.size == 1 + isEnablePadding.value = newValue == "RSA" } } label(messages["bits"]) - cbBits = combobox(selectedBits, bitsLists) { cellFormat { text = it.toString() } } + cbBits = combobox(selectedBits, ASYMMETRIC_ALGOS[selectedAlg.get()]) { cellFormat { text = it.toString() } } + label("padding:") + combobox(selectedPadding, RSA_PADDINGS) { + enableWhen(isEnablePadding) + cellFormat { text = it } + } + } + hbox { + addClass(Styles.center) togglegroup { spacing = DEFAULT_SPACING radiobutton(messages["encrypt"]) { isSelected = true } @@ -187,16 +196,16 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { action { isProcessing.value = true runAsync { genKeys(alg, listOf(selectedBits.value.toInt())) } ui - { - isProcessing.value = false - if (isPrivateKey) { - taInput.text = it[0] - taKey.text = it[1] - } else { - taInput.text = it[1] - taKey.text = it[0] + { + isProcessing.value = false + if (isPrivateKey) { + taInput.text = it[0] + taKey.text = it[1] + } else { + taInput.text = it[1] + taKey.text = it[0] + } } - } } } button(messages["deriveKey"]) { @@ -204,10 +213,10 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { action { isProcessing.value = true runAsync { catch({ it }) { taKey.text.privateKeyDerivedPublicKey(alg) } } ui - { - isProcessing.value = false - taOutput.text = it - } + { + isProcessing.value = false + taOutput.text = it + } } } } @@ -293,12 +302,12 @@ class AsymmetricCryptoView : Fragment(FX.messages["asymmetric"]) { outputEncode ) } ui - { - isProcessing.value = false - outputText = it - timeConsumption = System.currentTimeMillis() - startTime - labelInfo.text = info - if (Prefs.autoCopy) it.copy().also { primaryStage.showToast(messages["copied"]) } - } + { + isProcessing.value = false + outputText = it + timeConsumption = System.currentTimeMillis() - startTime + labelInfo.text = info + if (Prefs.autoCopy) it.copy().also { primaryStage.showToast(messages["copied"]) } + } } } diff --git a/app/src/test/kotlin/me/leon/asymmetric/Asymmetric.kt b/app/src/test/kotlin/me/leon/asymmetric/Asymmetric.kt index ab891acfb4..aa6eaf59ce 100644 --- a/app/src/test/kotlin/me/leon/asymmetric/Asymmetric.kt +++ b/app/src/test/kotlin/me/leon/asymmetric/Asymmetric.kt @@ -68,14 +68,14 @@ class Asymmetric { val testData = byteArrayOf(67) testData - .asymmtricEncrypt(pub.toPublicKey(alg), alg) + .asymmetricEncrypt(pub.toPublicKey(alg), alg) .run { asymmetricDecrypt(pri.toPrivateKey(alg), alg).contentEquals(testData) } .also { println(it) } val pubKey = pub.toPublicKey(alg).also { println(it?.encoded?.base64()) } val priKey = pri.toPrivateKey(alg).also { println(it?.encoded?.base64()) } - "hello".toByteArray().asymmtricEncrypt(pubKey, "SM2").also { + "hello".toByteArray().asymmetricEncrypt(pubKey, "SM2").also { println(it.base64()) it.asymmetricDecrypt(priKey, "SM2").also { println(it.decodeToString()) } } diff --git a/app/src/test/kotlin/me/leon/hash/HashTest.kt b/app/src/test/kotlin/me/leon/hash/HashTest.kt index 6bc9d3e12c..06c7bea6ed 100644 --- a/app/src/test/kotlin/me/leon/hash/HashTest.kt +++ b/app/src/test/kotlin/me/leon/hash/HashTest.kt @@ -123,6 +123,7 @@ class HashTest { "DSTU7564-512" to "e83945c9b56620e48b50eaf381c801078e05b89d85043ed5790596584d7057801" + "73c9d07ac2f0c559f05893d13ea9576d660ac0db5bb8885fac30a07a24ec51a", + "Skein-256-128" to "dfb6780585fcb71b7f8725f3b8bc3db5", "Skein-256-160" to "69bc779ef32b63ed641594cac645e9cf3540aa8f", "Skein-256-224" to "71a135876f540e96dc9b429ac733a55f6459e7bfe53f565bca800937", "Skein-256-256" to "86177f9baa4bd5466585a4fd78b3ebd595d83b29b7c1be57807165c36e42ff26",