Detect PEM file content: certificate or public/private key? - java

I am trying to detect the content of a PEM file. In case it contains certificate infos, the following code is perfect to get X509Certificates informations:
X509Certificate cert = X509CertUtils.parse(Files.readAllBytes(file.toPath()));
but returns NULL of course if it's a key instead of certificate.
So is there a proper way to detect PEM content (mayb PEMReader and then instance of on the result. I tried with a ---- PRIVATE KEY ----- file but it returned null also)?
Of course, I can manually detect if file contain -----BEGIN CERTIFICATE----- or -----BEGIN PRIVATE KEY----- but I find this very careless.
Thank you !

Related

how to serialize/deserialize X509Certificate

I see there is code to read one in here
https://docs.oracle.com/javase/8/docs/api/java/security/cert/X509Certificate.html
but there is no code for writing one out.
My preference is to write a String and read a String or else I will have to base64 encode. Anyways, how to serialize it?
thanks,
Dean
Use this to write a certificate as binary
Files.write(
Paths.get(fileName),
certificate.getEncoded());
And this code will write the certificate to base64
Files.write(
Paths.get(fileName),
Base64.getEncoder().encode(certificate.getEncoded()));
If you need a PEM file, just add -----BEGIN CERTIFICATE----- header and -----END CERTIFICATE----- footer to the base64 file
Java supports reading certificates encoded in PEM or binary format

How to sign and verify string using ssh key using java

I know this issue may be duplicated somewhere else, but i wasted a lot of time to fix this issue.
I need to use third party API and as per their documentation i have to generate private/public key using the command ssh-keygen -t rsa, send to them the public key and for every request i must sign the request body using my private key
i found many code sample to read private/public key of formats like pem or der, but not the format generated using ssh-keygen -t rsa
my private key now is
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,07E3CD04C0D5E7AEC5BFB3660C389A79
iP+UVOT9UUma638HRLzyd9hLeZGbs2NxTakIWCB5Inpvd5+O4vcdjNhmV3zxSyDY
JpHlU8417Fyn3qHjHbG2Tj86qgFeexcZ83pjXxFU8JnXfqutSe6Zpa4sDuZYKve6
Xv2oxF64pVqEesH+C9XOkyYiWVqr09vpKBlIM2GcI2WqQwLuDYhj/AAWJhpKGVJu
+fwiQj7VS+tzBE1QW4Kva5xwEE4z/XZHkYMNDHUXBPeifsYXwkz8ZcXlcVZ+CAql
jwKh4ORXkBO/Ok2wva3dFfU7no2YSNIDhgHFGK6C9n5igbstYbTEPEH/YeSbqz1L
SucLiftfdvL9UdFb1/NQfcFhusNPHctGybvfAzttQEfSU/W5OYcN25SKF5pHUtHZ
Widu5M3JFCJ5Gw0P2sjANZVN/+8p0alT61dy6OqLckJmJfixpkvRQqdEP8ucUlTe
r+X5Fe2xH+cYh2MLq9IXxrK4g0sUZKoZw4AGKq24CfvD2K7UqHlXVO1hocyhlq+m
rRCVvRLJc7mpvpBtIQ6qXbr1chMa3zgkf6jW9thJ40jt4Giarj5s80fSC3Dk3lQN
ENV7nnhmd2uzz5yXx4sITnoDnItYDcJZk5pcOR4FAjUR2wRaLokae0pdEbS4heMa
KPOGOZGJNxs2CpwFUZL3CKIVMOmh14pzjZ4DNb9yzVhyd6wag5HlN9JNB1322eDO
lzfEnyki45wVGnB6ChthOnDRdgP5CUK+eaGqO8BSS+wttR25+MbZEwyljoQXc59h
XbGL5qqxpzrIT9+wDrEq8QNUaIg5OEXvBLa3NVOWSStgx+q5gqb5mzwJVdJiqSfL
xGG0CcyKuDPi6Vt/GKx5SGYi0gHFBs3QlYwzvvBxb5xKTc/meQSCM2ALXuJrFjBT
hXCBRBQ4F6i3pnyqkPJ36hsQ/mv6AWtsNhkMs2LrMjic0Fl5OhU6m1YA1nx8qz8k
ZQBhSWxLaTVwQsYnkH6SApPSo0t+FIzQfpnyYj4A9o6uK3dOiXPZndKqKx4mwqwM
uszlfMobhZUn2+ZcILXSZb1nNrwHKANRsp+I4j8bjG7qYKS5dfPaeIxRVQnpCkK+
SVznB0x8/EtIb8mLvuFtQap9KQ1S5UQxF3HhFoHdKjbDlEhMI3KPzURgYpis8K0y
M6jUbBnFQog9rSRCM79qE/cK6FX/QHrZt1Ijb9sPo54Y1TJQhbTempQ8N8SLnJFE
SY7W9wqOjyjrIKJ1NAWVSAHKu3ctUZHqWqijykkGa/t09BmtKoaHJ3RTJmQ7r/Z2
nxnARy9lDBSXgp8ErcYcf1eeRtCeRMZY+22F8gD7jJ/uKeEj6k8oUITt/dYSJWeA
LI9rPYydva8cNi0RtcB8Vgddi+GnhnGnhIXs3swk4AiVhBAPlAEfMdp3MjARrkJI
2UuMHStfht96aD3x3mL4fP0o6fJ5jSj/aCepwuR18xUHgtCCO8Sj81NBwPTSv654
XzIngNY3OPAOqo3RmS+xSnH8sCwE/wJxVu2sa/Ue8XszsjrzO4plYKh344MdR6g3
ISWyjPnFsdL1gBxoiPGfM/EF0bd4a1iGHDk4Ih4AcPgpgMwgN2VYDvGcxHEkQ0Y9
-----END RSA PRIVATE KEY-----
my public key
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ98gmTkAoteabP96SmMDWAsPYIj5tV4iovMC9IEeWtiV1DbOIYVYpp27YM2DezoEuBwbccG9+A2wygyYKAVJurfmQTTL4h2WxJ5UIRJtwKrc2UKZNA6amUfIEcQHt0qJeTk6t5Havte2eTU3P6p15J7sHonLdeVBqybjeUMTOc8g41uUtTtmgTSp3BORkY/qwYzC7bICWZuuoklathRgj0CATkfkz25kggV/cNiWo8Ngr2mM8qB3EZxidF6FYwGROYRFq9jPfn1K3EvgOWWsPeHwd/bJn109sTqaLY5TsKuatxZAE+3CHNoQsEGaAVtEz505Oa8IRJYp9LERuBHx1 melad#pcwrk005.bovc.dk
how to read these files using java and sign,verify strings using them

Java verify digital signature in openssl [duplicate]

This question already has an answer here:
Why are the RSA-SHA256 signatures I generate with OpenSSL and Java different?
(1 answer)
Closed 6 years ago.
Using this tutorial, I created a Java program what can sign a document with SHA256withRSA algorithm. In the output I get a public key and a signature file.
I try to verify my file with openssl, but I can't... I was searching on the net and I found that I need to have a standard .pem key maybe, so my question is: How can I convert my key to pem format? Or can I generate a .pem key in Java? And if it's a wrong way, how can I verify my signature?
A PEM file contains the public key binary data encoded in base64 and splitted in lines of 64 characters. The file has also the header -----BEGIN PUBLIC KEY----- and the footer -----END PUBLIC KEY-----
Java has not a native converter to PEM but you can use bouncycastle
PEMWriter pemWriter = new PEMWriter(new FileWriter(file));
pemWriter.writeObject(publicKey);
pemWriter.flush();
pemWriter.close();
Alternatively you can verify a signature with openssl using a binary key format using
-keyform DER
Then save the content of your publicKey in a file
byte publicKeyDer[] = publicKey.getEncoded()

Convert certificate string to byte array

I got a string represents PEM certificate:
-----BEGIN CERTIFICATE-----
MIICUTCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADBXMQswCQYDVQQGEwJDTjEL
MAkGA1UECBMCUE4xCzAJBgNVBAcTAkNOMQswCQYDVQQKEwJPTjELMAkGA1UECxMC
VU4xFDASBgNVBAMTC0hlcm9uZyBZYW5nMB4XDTA1MDcxNTIxMTk0N1oXDTA1MDgx
NDIxMTk0N1owVzELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAlBOMQswCQYDVQQHEwJD
TjELMAkGA1UEChMCT04xCzAJBgNVBAsTAlVOMRQwEgYDVQQDEwtIZXJvbmcgWWFu
ZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCp5hnG7ogBhtlynpOS21cBewKE/B7j
V14qeyslnr26xZUsSVko36ZnhiaO/zbMOoRcKK9vEcgMtcLFuQTWDl3RAgMBAAGj
gbEwga4wHQYDVR0OBBYEFFXI70krXeQDxZgbaCQoR4jUDncEMH8GA1UdIwR4MHaA
FFXI70krXeQDxZgbaCQoR4jUDncEoVukWTBXMQswCQYDVQQGEwJDTjELMAkGA1UE
CBMCUE4xCzAJBgNVBAcTAkNOMQswCQYDVQQKEwJPTjELMAkGA1UECxMCVU4xFDAS
BgNVBAMTC0hlcm9uZyBZYW5nggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEE
BQADQQA/ugzBrjjK9jcWnDVfGHlk3icNRq0oV7Ri32z/+HQX67aRfgZu7KWdI+Ju
Wm7DCfrPNGVwFWUQOmsPue9rZBgO
-----END CERTIFICATE-----
I assigned the above string to String variable String myCertStr.
What is the proper way to convert myCertStr to DER encoded byte[]?
(I am using Java 7, and I am not interested to use 3rd party library for this, I am seeking for a JDK7 way of doing it.)
IMPORTANT
As #dave_thompson_085 has pointed out in the comments, SunJCE CertificateFactory is indeed capable of parsing PEM files.
So you can just use that to get the Certificate object
as detailed at How to load public certificate from pem file..? (which is an earlier answer by #dave on the same topic, so please upvote it, instead of this one, if you find this useful !), and then access its encoded (DER) form.
However, if your PEM file is a raw "RSA PUBLIC KEY" (like the one that was attached to this question), or some other entity which SunJCE implementation can not parse directly, you can still parse and decode it manually, as detailed below.
Technically what you have here is not a certificate, but just a public key.
You can decode it to DER bytes as simple as that:
byte[] derBytes = Base64.getDecoder().decode(
pemText.replaceAll("-----(BEGIN|END) RSA PUBLIC KEY-----", "").replaceAll("\n", "")
);
Note, that what you will get will be a raw RSA (PKCS#1) key:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
You can use the same technique to decode X.509 certificates or private keys.
E.g. the code to decode the X.509 certificate:
byte[] certificateBytes = Base64.getDecoder().decode(
pemText.replaceAll("-----(BEGIN|END) CERTIFICATE-----", "").replaceAll("\n", "").getBytes("UTF-8")
);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)(certificateFactory.generateCertificate(
new ByteArrayInputStream(certificateBytes)
)
);
UPDATE
The code above uses Java 8 Base64 decoder.
As question has been updated asking for a Java 7 solution,
here is a link to an excellent thread, discussing various options available: Base64 Java encode and decode a string.
E.g. java.xml.bind method described there does not require any extra libraries on Java 7 (which seems to match what OP wants)

Help verifying RSA signed text with Python

Using Java I have created RSA keypairs. Using Java I can use these keys to sign and verify some text. I can also "export" these keys in PEM format and load them into a Python test script. Once in the Python script, I can use these keys to sign and verify some text using M2Crypto.
I have not yet been able to verify in Python the signature I created in Java.
Right now I am just trying to get cross-platform signing and verifying to work.
Here is Java snippet:
Signature sig = Signature.getInstance("MD5WithRSA");
sig.initSign(key.getPrivate());
sig.update("This is a message.".getBytes("UTF8"));
byte[] signatureBytes = sig.sign();
return Base64.encodeBytes(signatureBytes, Base64.DO_BREAK_LINES);
Which generates:
PIp4eLhA941xmpdqu7j60731R9oWSNWcHvwoVADKxABGoUE02eDS0qZ4yQD2vYBdRDXXxHV4UjtW
YQwv9nsOzCBWeDQ0vv6W0dLVfTBuk79On7AALuwnTFr8s0y5ZN5RINvPPR60mwONav26ZbPj4ub3
NZqUS/zkqyO8Z8D2zUjk0pqAhWDGbFBaWPQJBPOY9iRt8GlsAUkGfYGeIx9DNU8aiJmQ3NnUHbs4
5NEr3xydbNJjwK96kkNJ9vyKZRfnNd4eW2UllPiwJSRQgefCQfh79ZuiYeQEuk3HMh7Si4iYl7uU
rWCgYFl4fGV1X/k+BSHR4ZZFWGQ3IPfafYHyNw==
And here is the public key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg+N7xQHVHU3VHMZ9VGFdUf6ud3rAL8YS
sfWv2zFMnKAjh6XacwDGX6jJR/0/pyDriRGw/uodBDSFvgn9XEM/srMYtbJ1KQ9R9ChDifixF3Hx
yzbzPRvFoEfZnS/63+d1r0wnafz7xx0eDEYE3TgRKTMikwOsuIOFWa7GhA4BvP7ad79bI5ORJdLu
9Je+k+4dbt0xk2t7YopxYmyU+4zhZMxuthJTr69rXgqhgsCRdK6kFIGm3YuJ1WQcci8OVwH+3o7F
XzJHpSTxH57m6PX5lXaywIDCbUauTpBV3w+0vTeGI/2o+U40qhLBkpZT9GSVKxgXl5a0XxrkwTGn
61XZqQIDAQAB
-----END PUBLIC KEY-----
Then in Python the key is loaded and the signature is attempted to be verified:
from M2Crypto import RSA, EVP
pub_key = RSA.load_pub_key('public_key.pem')
verify_evp = EVP.PKey()
verify_evp.assign_rsa(pub_key)
verify_evp.verify_init()
verify_evp.verify_update("This is a message.")
if verify_evp.verify_final(sig_string.decode('base64')) == 1:
print "Good"
else:
print "Bad"
And this does not verify. I suspect it is some leading or trailing characters or encoding weirdness that I don't understand.
I have no particular attachement to M2Crypto and have played a bit with the gdata.tlslite modules as well.
Please note that the keys are working, and that the text and signature above verify in Java, and the keys (public and private) can be used within Python to sign and verify text. The problem is somewhere in how Java-generated signature and/or the message text is getting into the Python code.
What am I doing wrong?
M2Crypto.EVP defaults to 'sha1' (SHA1) and you're using MD5WithRSA. I think you should switch SHA1WithRSA (MD5 is a very weak algorithm).

Categories

Resources