whyoleg/cryptography-kotlin

Can I set my PublicKey in "provider.get(RSA.PSS)" ?

thanhhoai162963 opened this issue · 11 comments

val ecdsa = provider.get(ECDSA)
val keyPairGenerator = ecdsa.keyPairGenerator(EC.Curve.P521)
val keyPair: ECDSA.KeyPair = keyPairGenerator.generateKey()

I wasn't found setPublicKey()

Hey, Im not sure what do you mean by setPublicKey. What use case do you have? What are you trying to do?

I use asymmetric encryption which connect resful api. I get rsaPublicKey from api server (not need encryption).
After I need set publickKey with rsaPublicKey and key random from local to encrypt(k) call api.

Example:
fun encryptData(dataDes: String): String? {
return try {
val c = Cipher.getInstance(Algorithm.RSA_OAEP)
c.init(Cipher.ENCRYPT_MODE, Key.rsaPublicKey()) // rsaPublicKey I get from api
val encryptOut = c.doFinal(dataDes.toByteArray()) // dataDes random char()
org.bouncycastle.util.encoders.Base64.toBase64String(encryptOut) // result "k" to call api asymmetric encryption
} catch (e: Exception) {

    }
}

As far as I understand you need to decode key from binary representation and then use it. In this case you will need something like:
ECDSA:

val ecdsa = provider.get(ECDSA)
val publicKey = ecdsa.publicKeyDecoder(EC.Curve.P521).decodeFrom(EC.PublicKey.Format.RAW, keyByteArray) // or other format
// and then do anything with key verify or encrypt

Similar for RSA-OAEP:

val rsa = provider.get(RSA.OAEP)
val publicKey = rsa.publicKeyDecoder(SHA256).decodeFrom(RSA.PublicKey.Format.DER) // or other format
// and then do anything with key verify or encrypt

Does it helps?

val publicKey = rsa.publicKeyDecoder(SHA256).decodeFrom(RSA.PublicKey.Format.DER, myKey)
//Follow I understand, Can I set publicKey = "myKey" here?

I mean i can init val rsa = provider.get(RSA.OAEP) with myKey, after I encrypt data combine (RSA.OAEP)contain mykey as

c.init(Cipher.ENCRYPT_MODE, myKey) // rsaPublicKey I get from api
val encryptOut = c.doFinal(data) // dataDes random char()

Follow I understand, Can I set publicKey = "myKey" here?

Yeah, though, myKey should be a ByteArray, not a String. DER format is the same format which is used in JDK APIs by default for RSA keys.

 fun encryptData(dataRandom: String): String? {
        return try {
            val c = Cipher.getInstance("RSA/ECB/OAEPPadding")
            c.init(Cipher.ENCRYPT_MODE, loadPublicKey())
            val encryptOut = c.doFinal(dataRandom.toByteArray())
            org.bouncycastle.util.encoders.Base64.toBase64String(encryptOut)
        } catch (e: Exception) {
            Log.d("error:", "error")
            ""
        }
    }
    
      @Throws(GeneralSecurityException::class, IOException::class)
    private fun loadPublicKey(): PublicKey? {
        val rsaPublicKey = runBlocking {
            LizAiDataStore.instance.getRsaPublicKey()?.publicKey
        }
        val data = Base64.decode(rsaPublicKey)
        val spec = X509EncodedKeySpec(data)
        val fact = KeyFactory.getInstance(Algorithm.RSA)
        return fact.generatePublic(spec)
    }
    
Thanks you very much recommend you @whyoleg  , after 3 days thinking, learn about
from website, ,convery swift xcode - to kotlin mutiilplatform, I still can't convert this code. Looking forward to your suggestions

Looks like I really need to create a guide for JDK APIs to cryptography-kotlin conversion, as you are not the only one who is struggling with it :)

Here is a one way to do this:

fun encryptData(data: String): String? {
  val key = loadPublicKey() ?: return null
  val encryptOut = key.encryptor().encrypt(data.encodeToByteArray())
  return Base64.encode(encryptOut)
}

private fun loadPublicKey(): RSA.OAEP.PublicKey? {
  val rsaPublicKey = runBlocking { LizAiDataStore.instance.getRsaPublicKey()?.publicKey } ?: return null
  val encodedKey: ByteArray = Base64.decode(rsaPublicKey)
  return CryptographyProvider.Default.get(RSA.OAEP)
               .publicKeyDecoder(SHA256)
               .decode(RSA.PublicKey.Format.DER, encodedKey)
}

Notes:

  • Base64 here is using kotlin Base64
  • I've omitted some details, to keep intention clear

Thank you @whyoleg. I generated encryptOut. But my server not decrypt . My server use dot Net rsa oeap follow:
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsacryptoserviceprovider?view=netcore-3.1
keySize: 2048

Looks like .NET is using RSA OAEP with SHA1 - hint on SO: https://stackoverflow.com/a/67793433
So you need to try publicKeyDecoder(SHA1) instead

Thanks you very much @whyoleg , it working. Special thanks.
And Can I use triple des algorithm as android ?

mySecretKeyFactory = SecretKeyFactory.getInstance("DESede")
cipher = Cipher.getInstance("DESede")
key = mySecretKeyFactory?.generateSecret("DESede")

Cool! I'm closing an issue! JDK to cryptography-kotlin guide will be tracked in #24