Ray*_*kud 4 java encryption rsa kotlin
我一直在尝试使用预制公钥加密 Kotlin/Java 中的一个简单字符串,但没有成功。这是我目前正在做的事情,评论是我目前尝试过的。
val toEncrypt = "8uUrfe4OcJVUT5lkAP07WKrlGhIlAAwTRwAksBztVaa0hHdZp50EFjOmhrAmFsLQ"
val publicKeyRaw =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCAW4WQxF2/qzqYwoQlwkkQIjQJ\n" +
"hCm2Hjl00QGkxeO12Py+jytTNYAopHCPpR4SbhE1cFdYx1qjEnFbgeJBxFENyqDg\n" +
"GvBhlwrWQXfI9LdA2M3xbr/4wur7ph1c+aQxOpImzslCtHJ5df7cyFrOTnkY+XYY\n" +
"yGK2Fsnu67FKWjgVvQIDAQAB\n" +
"-----END PUBLIC KEY-----"
val reader = PemReader(StringReader(publicKeyRaw))
val pemObject = reader.readPemObject()
val keyBytes: ByteArray = pemObject.content
val keySpec: EncodedKeySpec = X509EncodedKeySpec(keyBytes)
val keyFactory = KeyFactory.getInstance("RSA")
val key = keyFactory.generatePublic(keySpec)
val cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.ENCRYPT_MODE, key)
val cipherData: ByteArray = cipher.doFinal(toEncrypt.toByteArray())
val encryptedData = Base64.encodeToString(cipherData, Base64.DEFAULT)
Log.e("TAG", "encryptedData: $encryptedData")
Run Code Online (Sandbox Code Playgroud)
这是我已经尝试过的代码:
/*
val publicKey = publicKeyRaw.replace("\n", "")
.replace("\\n", "")
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
*/
/*
val pemParser = PEMParser(StringReader(publicKeyRaw))
val pemKeyPair : PEMKeyPair = pemParser.readObject() as PEMKeyPair
val key = JcaPEMKeyConverter().getPublicKey(pemKeyPair.publicKeyInfo)
*/
/*
val keyFactory = KeyFactory.getInstance("RSA")
val keyBytes: ByteArray = Base64.decode(publicKey.toByteArray(), Base64.DEFAULT)
val spec = X509EncodedKeySpec(keyBytes)
val fileGeneratedPublicKey = keyFactory.generatePublic(spec)
val rsaPub: RSAPublicKey = fileGeneratedPublicKey as RSAPublicKey
val publicKeyModulus: BigInteger = rsaPub.modulus
val publicKeyExponent: BigInteger = rsaPub.publicExponent
val keyFactoryAlt = KeyFactory.getInstance("RSA")
val pubKeySpec = RSAPublicKeySpec(publicKeyModulus, publicKeyExponent)
val key = keyFactoryAlt.generatePublic(pubKeySpec) as RSAPublicKey
*/
/*
val reader = PemReader(StringReader(publicKeyRaw))
val pemObject = reader.readPemObject()
val keyBytes: ByteArray = pemObject.content
val keySpec: EncodedKeySpec = X509EncodedKeySpec(keyBytes)
val keyFactory = KeyFactory.getInstance("RSA")
val key = keyFactory.generatePublic(keySpec)
*/
/*
val keyFactory = KeyFactory.getInstance("RSA")
val keyBytes: ByteArray = Base64.decode(publicKey.toByteArray(), Base64.DEFAULT)
val spec = X509EncodedKeySpec(keyBytes)
val fileGeneratedPublicKey = keyFactory.generatePublic(spec)
val rsaPub: RSAPublicKey = fileGeneratedPublicKey as RSAPublicKey
val publicKeyModulus: BigInteger = rsaPub.modulus
val publicKeyExponent: BigInteger = rsaPub.publicExponent
*/
/*
val pemParser = PEMParser(StringReader(publicKey))
val pemKeyPair : PEMKeyPair = pemParser.readObject() as PEMKeyPair
val encoded : ByteArray = pemKeyPair.publicKeyInfo.encoded
val keyFactory = KeyFactory.getInstance("RSA")
val key = keyFactory.generatePublic(PKCS8EncodedKeySpec(encoded))
*/
Run Code Online (Sandbox Code Playgroud)
它实际上生成一个字符串,但是当使用以下工具时: https: //8gwifi.org/rsafunctions.jsp 它显示一个错误,它无效,即使很困难我在那里生成了密钥大小为 1024 的密钥
我的问题是:如何在 Java/Kotlin 中使用这种密钥进行加密。(您可以在您喜欢的任何网站或提供的网站上生成此类密钥)
这是我用过的一对:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCAW4WQxF2/qzqYwoQlwkkQIjQJ
hCm2Hjl00QGkxeO12Py+jytTNYAopHCPpR4SbhE1cFdYx1qjEnFbgeJBxFENyqDg
GvBhlwrWQXfI9LdA2M3xbr/4wur7ph1c+aQxOpImzslCtHJ5df7cyFrOTnkY+XYY
yGK2Fsnu67FKWjgVvQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCAW4WQxF2/qzqYwoQlwkkQIjQJhCm2Hjl00QGkxeO12Py+jytT
NYAopHCPpR4SbhE1cFdYx1qjEnFbgeJBxFENyqDgGvBhlwrWQXfI9LdA2M3xbr/4
wur7ph1c+aQxOpImzslCtHJ5df7cyFrOTnkY+XYYyGK2Fsnu67FKWjgVvQIDAQAB
AoGActBq8wmTSiVh7s7f4d6d+D6ACZscrHjwsBtcuwUAIOONgO8TtASBNNmSjgsG
kTm/TuvEVfdMjd2rZE0UE/wE+2BOoHTlkVjcKMxoM8KbP/4RBDYlYmWTseiS8zmp
dGwchOzsoWKnhZtnvMrki0f1SdMq4J6g9RncFIrUSKWJ1MECQQDp0s4v+sKo423X
2YSAhB8j1LMPoRlioXSmvVrHGINzGoHt2tRvGqqHaHbd/9QkkhpfeeBcdrv/xOaH
fVH08dnJAkEAjIgFRe6QEDNvm1qCRx6ata047N188MxdHgKHwQBsv48dxqljQrFS
N1yEfXsv6PjLk3DCD8Wi3FTOgftpZVeWVQJBAIpc+TABJkGEW1KYX8Ug6cBtNAxy
my/3NK0abeZUxixNqkcS8BRS5kg8c+KIaYO+hSasWyy8AiGm5XeVm/LjTqkCQEGQ
dGVcF/p3BOsGHyHvNV7tolFgRJpTvl3x8EQrXpFAxDObc6P59tG9aFLi1kdrTA9N
3DxfiMwjBPW/xjxx0MECQBtaSSfTNUYBP64+evjY4HaV9GI5AK83webyF73axXIq
4dyadIdIo78Yaz+f2myX7vyfUlU5iM8QuPMN2KCM3CE=
-----END RSA PRIVATE KEY-----
Run Code Online (Sandbox Code Playgroud)
这是我使用的代码: https: //github.com/Raykud/TestEncryption
编辑:这是生成的加密文本。
NO_WRAP: c6nQMEFIrOWsPjB6W00DC6+5xaKm8R79bu8xLz9+yYhDTDepkiQGh0fWpyJuldNJit5CyL9n73TQxMjmtqsZsR/sAGEFjk7EGj8etwFO4MKpZY55BX1MsOVbWbfo2x31uCb/Ssd6nJnu897yCD5Md7xKqbovZP8eoZrvp2azFOk=
DEFAULT:
c6nQMEFIrOWsPjB6W00DC6+5xaKm8R79bu8xLz9+yYhDTDepkiQGh0fWpyJuldNJit5CyL9n73TQ
xMjmtqsZsR/sAGEFjk7EGj8etwFO4MKpZY55BX1MsOVbWbfo2x31uCb/Ssd6nJnu897yCD5Md7xK
qbovZP8eoZrvp2azFOk=
Run Code Online (Sandbox Code Playgroud)
问题的原因是使用了不同的填充。
如果不应用填充,则可以复制(使用发布的公钥)或解密(使用发布的私钥)发布的密文(RSA/ECB/NoPadding
请参阅此处)。这种 RSA 变体称为教科书 RSA,不应该在实践中使用,因为它不安全。该网站应用PKCS#1 v1.5 padding(前三个选项)或OAEP(后三个选项),完全不支持不安全的教科书RSA。即填充不兼容,因此解密失败。
有两种方法可以指定加密Cipher#getInstance
,完整变体算法/模式/填充或短变体算法,请参见此处。在后者中,模式和填充由特定于提供者的默认值确定。由于它们是特定于提供商的,因此它们在不同的环境中可能会有所不同,这可能会导致跨平台问题,就像在本例中一样。这就是为什么应始终使用完整版本的原因!
Cipher#getInstance("RSA")
显然在您的环境中应用了教科书 RSA,即没有填充。我可以在 Android Studio(API 级别 28)中重现此行为。相反,在 Eclipse(Kotlin 插件 0.8.14)中使用 PKCS#1 v1.5 填充。
所以问题的解决方案是根据使用的环境显式指定填充,例如对于 PKCS#1 v1.5 填充通常使用RSA/ECB/PKCS1Padding
或RSA/NONE/PKCS1Padding
,请参见此处。请注意,方案算法/模式/填充可用于对称和非对称加密。虽然操作模式是为对称加密定义的,但通常没有为非对称加密(例如 RSA)定义,即 ECB 在 RSA 上下文中没有任何意义,但仍被某些提供商在规范中使用。
另一个可能的问题是网站无法处理换行符,但它不会自动删除换行符,因此如果密文包含换行符,解密就会失败。该选项Base64.DEFAULT
在 76 个字符后生成换行符。因此,在使用网站对密文进行解密之前,必须将这些内容删除(例如手动)。或者,Base64.NO_WRAP
可以使用,它在一行上生成密文。