Android Question OpenSSL RSA - PrivateKeyFromBytes always gives me an error

mmanso

Member
Licensed User
Hi all,

I'm having a problem trying to use a rsa private key to sign a string. What I've did was to create a 1024 rsa private key with the command:

Bash:
openssl genrsa -out private_key.pem 1024
And then, I try to use it like this:

B4X:
Dim privkey() As Byte
Dim su As StringUtils
Dim TestKPG As KeyPairGenerator
Dim privateKey As String = "MIICXQIBAAKBgQDNTfxYISc/rIjvAWlOIJJNBZF53ttEhKK2jMp+ozZYKElar/e/AtSn+Rmjlceycf6wo/2xrlLTQZlSX60jT1gRdN3jAeVKuNKFLhGr4/C+0wcudk90f3JFpWPW9/kmI/8tWqSoWzoMxo9UejXtt7qOIEP/o5noOZuLutg5iOunQIDAQABAoGBAL7TVNDJiASsJt8YTbv7lGCY414GoYHvUpohBPpuU83fLEdptfpJ9EVoyMb/Kg2X3WZsFxs27+9CUvN40KI4Vp7A2n5a8gus0cenYVNZRhYV+Ebzc2PGjyV8pyJMY32Q7RejzBp3GoCyrNjzotwpHsAFSjCdhX4M+V8w5+/YSVAkEA6n8ILtW6YWrryFwQfmUBX+KI4gdDegumnxGbS8oIWEIQolZEPQ0W4JjRUEQcOO1hYYHUkMiMNIakCLcHFXrvKwJAOAhqQFYpwcKhL7DGTLDqHQWUyJeMyoMBF3e07a16Iiysxk4u/XqAgqsVmc/Kya+yizGVcCPxtlDJr3OOfFJtVcCQCCeIulA2XgLg1iPVcv/CL3pqNin4f7r9/VQYaWdKKP+LIooLb3AQFplZ1ge4T4Z53FTWgGPVphEBgWPWoDe5kCQQDByxjwexDgu62Pq+2rwRV0WqFDRCQFJSLZb4OrpZoMKEdHdZC/zrg5Nk33M91BwRHaqRsYRrjuvmtPDnN3N/49AkAViIwc7ylIGXPx9yhQoqBiL78tLm6zyflXlkQcEHDFU1xrYXdFgBjT+kJJ2M9o0B845YAicdkUwHYvShuRm8P"

privkey = su.DecodeBase64(privateKey)
Log(privkey.Length) ' returns 609
TestKPG.Initialize("RSA", 1024)
TestKPG.PrivateKeyFromBytes(privkey) ' allways throws an error
The error I get is this one:

B4X:
Error occurred on line: 223 (ServerService)
java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag
    at org.apache.harmony.xnet.provider.jsse.OpenSSLKey.getPrivateKey(OpenSSLKey.java:124)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLRSAKeyFactory.engineGeneratePrivate(OpenSSLRSAKeyFactory.java:64)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:186)
    at anywheresoftware.b4a.agraham.encryption.CipherWrapper$KeyPairGeneratorWrapper.PrivateKeyFromBytes(CipherWrapper.java:457)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:777)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:354)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.debug.Debug.delegate(Debug.java:262)
    at b4a.example.serverservice._handlesignstring(serverservice.java:506)
    at b4a.example.serverservice._server_handlerequest(serverservice.java:618)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:351)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:176)
    at anywheresoftware.b4a.objects.Servlet$2.run(Servlet.java:87)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag
    at org.apache.harmony.xnet.provider.jsse.NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(Native Method)
    at org.apache.harmony.xnet.provider.jsse.OpenSSLKey.getPrivateKey(OpenSSLKey.java:122)
    ... 33 more
Now, after reading the forum and trying a lot of stuff, I came to the conclusion that if I create my own private key in B4A with this code:

B4X:
Dim RSAOwnPrivKeyBytes(0) As Byte
Dim RSAOwnKPG As KeyPairGenerator

RSAOwnKPG.Initialize("RSA", 1024)
RSAOwnKPG.GenerateKey
RSAOwnPrivKeyBytes=RSAOwnKPG.PrivateKeyToBytes
Log(RSAOwnPrivKeyBytes.Length) ' returns 634
From the first example, if I use

B4X:
TestKPG.PrivateKeyFromBytes(RSAOwnPrivKeyBytes)
The call to the PrivateKeyFromBytes works without any problem.

Thinking that I might have a problem on my private key generation, I went to the website - http://travistidwell.com/jsencrypt/demo/ - which I've seen on a post in the forum and I've generated a 1024 RSA private key there. The problem I have is the same that when using mine...

Since I'm kind lost here, I would appreciate that if someone has experience in this subject and could point me out any direction, I would be grateful.

Thanks a lot in advance.
 

KMatle

Expert
Licensed User
It's all about formatting the keys. Use this to generate keys "outside" of B4x (like here with OpenSSL):

B4X:
cd C:\xampp\apache\bin
openssl genrsa  -out PrivateKey.pem 1024
openssl pkcs8 -topk8 -inform pem -in PrivateKey.pem -outform pem -nocrypt -out C:/PrivateKey.pem
openssl rsa -pubout -in PrivateKey.pem -out C:/rsa/PublicKey.pem
Then you get the public and private key in a "human readble format":

-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----
Here you recognize the header and the footer ("-----BEGIN RSA PUBLIC KEY-----" and "-----END RSA PUBLIC KEY-----"). Betweet there's the public key (Base64 formatted).

Next step is to remove the header and the footer (via String.Replace): Do not forget to remove the CRLF. Convert the Base64 to a Byte array and load the key. That's all. Same with the private key.

Vice versa you neet to convert the "B4x keys" (these are bytes) to a Base64 string and add the header and the footer plus CRLF. and use it in php or any other platform.

Note: If you only need the keys inside B4x you don't need to create any in OpenSSL (like you have discovered on your own).

Here's some of my code I use in B4x:

B4X:
RSAOwnC.Initialize("RSA/ECB/PKCS1Padding") ' compatible with OpenSSL if your add the headers
RSAOwnKPG.Initialize("RSA", RSAKeySize) 'Global var like 4096
RSAOwnKPG.GenerateKey
RSAOwnPrivKeyBytes=RSAOwnKPG.PrivateKeyToBytes
RSAOwnPubKeyBytes=RSAOwnKPG.PublicKeyToBytes
To sign and verify a message:

B4X:
Sub SignMessage (MessB() As Byte) As Byte()
    Dim Sign As Signature
    Sign.Initialise("SHA256withRSA",Sign.SIGNATURE_SIGN,RSAOwnKPG.PrivateKey)
    Sign.Update(MessB)
    Return Sign.Sign
End Sub
B4X:
Dim SignVerify As Signature
SignVerify.Initialise("SHA256withRSA",Sign.SIGNATURE_VERIFY,RSAOwnKPG.PublicKey)
SignVerify.Update(data)
Log(SignVerify.Verify(b))
 
Top