问题
Below is my requirement:
- Program will have an xml file as input with 3 tags: , and . All these data are Base64 encoded. Note: Program is using BC jars
- Program needs to decode them and verify the data for its authenticity using the signature and certificate
- Verified data should be Base64 decoded and written into another file
Below is my code which tries to decode the certificate:
public void executeTask(InputStream arg0, OutputStream arg1) throws SomeException{
try{
BufferedReader br = null;
br = new BufferedReader(new InputStreamReader(arg0));
String orgContent = "", splitData = "", signContent = "", certContent = "";
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(arg0);
doc.getDocumentElement().normalize();
NodeList originalContent = doc.getElementsByTagName("OrgContent");
Element originalElement = (Element)originalContent.item(0);
NodeList textOrgContent = originalElement.getChildNodes();
orgContent = ((Node)textOrgContent.item(0)).getNodeValue().trim();
NodeList signature = doc.getElementsByTagName("Signature");
Element signatureElement = (Element)signature.item(0);
NodeList signatureContent = signatureElement.getChildNodes();
signContent = ((Node)signatureContent.item(0)).getNodeValue().trim();
NodeList certificate = doc.getElementsByTagName("Certificate");
Element certificateElement = (Element)certificate.item(0);
NodeList certificateContent = certificateElement.getChildNodes();
certContent = ((Node)certificateContent.item(0)).getNodeValue().trim();
String decodedCertContent = new String(Base64.decode(certContent),StandardCharsets.UTF_8);
byte[] certByteValue = Base64.decode(certContent);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
System.out.println("certContent:\n" + new String(certByteValue,StandardCharsets.UTF_8));
InputStream inputStream = new ByteArrayInputStream(Base64.decode(certContent));
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(inputStream);
arg1.write(decodedOrgData.getBytes());
arg1.flush();
}
catch (ParserConfigurationException e){
e.printStackTrace();
}
catch (IOException e){
e.printStackTrace();
}
catch (org.xml.sax.SAXException e){
e.printStackTrace();
}
catch (CertificateException e){
e.printStackTrace();
}
}
When I print the value of new String(certByteValue,StandardCharsets.UTF_8) the program is printing some unrecognizable text. When executing the last line of the code X509Certificate cert = (X509Certificate)certFactory.generateCertificate(inputStream);
system is throwing java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Invalid BER/DER data (too huge?).
Since I am a newbie to these Certificates thing, I have hit a deadlock. I am unable to proceed with the requirement. I would like to know how to achieve my above said requirements.
Edit The input stream to the above code will be an xml file. Another program creates that xml file with base64 encoded data with signature and certificate. In that program, for encoding the certificate the below code is used:
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("Filepath/certificate.p12"), "password".toCharArray());
PrivateKey privateKey = (PrivateKey)keyStore.getKey(alias, "password".toCharArray());
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) factory.generateCertificate(new FileInputStream("D:/Sujai/Implementation Team/PI/Axis Treds/Certificates/PI_7.5_Cert/Arteria_Certificate-cert.cert"));
byte[] encodedCert = certificate.getEncoded();
String encodedStringCert = new String(Base64.encode(new String(encodedCert).getBytes(StandardCharsets.UTF_8)));
The variable encodedStringCert is passed as the certificate value inside a tag. In the program shared at the top of this question, I need to decode this certificate value.
Sample certificate content: -----BEGIN CERTIFICATE----- MIIDBjCCAe6....IM1g== -----END CERTIFICATE-----
回答1:
new String(certByteValue,StandardCharsets.UTF_8)
fails because the certificate encoded data is not representable as string
The problem could be that the source data is not a base64 X509 certificate, or a encoding issue with your library Base64.decode()
. I suggest use the standard decoder of java 8 Base64.getDecoder().decode()
or DataTypeConverter.parseBase64Binary()
for java >6
Check also this working code to decode a base64 encoded certificate
String certB64 = "MIIHFDCCBfygAwIBAgIIK2o4sL7KHQgwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTYxMjE1MTQwNDE1WhcNMTcwMzA5MTMzNTAwWjBmMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEVMBMGA1UEAwwMKi5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEG1y99TYpFSSiawnjJKYI8hyEzJ4M+IELfLjmSsYI7fW/V8AT61quCswtBMikJYqzYBZrV2Reu5sHlLr6936cR6OCBKwwggSoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCCA2sGA1UdEQSCA2IwggNeggwqLmdvb2dsZS5jb22CDSouYW5kcm9pZC5jb22CFiouYXBwZW5naW5lLmdvb2dsZS5jb22CEiouY2xvdWQuZ29vZ2xlLmNvbYIWKi5nb29nbGUtYW5hbHl0aWNzLmNvbYILKi5nb29nbGUuY2GCCyouZ29vZ2xlLmNsgg4qLmdvb2dsZS5jby5pboIOKi5nb29nbGUuY28uanCCDiouZ29vZ2xlLmNvLnVrgg8qLmdvb2dsZS5jb20uYXKCDyouZ29vZ2xlLmNvbS5hdYIPKi5nb29nbGUuY29tLmJygg8qLmdvb2dsZS5jb20uY2+CDyouZ29vZ2xlLmNvbS5teIIPKi5nb29nbGUuY29tLnRygg8qLmdvb2dsZS5jb20udm6CCyouZ29vZ2xlLmRlggsqLmdvb2dsZS5lc4ILKi5nb29nbGUuZnKCCyouZ29vZ2xlLmh1ggsqLmdvb2dsZS5pdIILKi5nb29nbGUubmyCCyouZ29vZ2xlLnBsggsqLmdvb2dsZS5wdIISKi5nb29nbGVhZGFwaXMuY29tgg8qLmdvb2dsZWFwaXMuY26CFCouZ29vZ2xlY29tbWVyY2UuY29tghEqLmdvb2dsZXZpZGVvLmNvbYIMKi5nc3RhdGljLmNugg0qLmdzdGF0aWMuY29tggoqLmd2dDEuY29tggoqLmd2dDIuY29tghQqLm1ldHJpYy5nc3RhdGljLmNvbYIMKi51cmNoaW4uY29tghAqLnVybC5nb29nbGUuY29tghYqLnlvdXR1YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYqLnlvdXR1YmVlZHVjYXRpb24uY29tggsqLnl0aW1nLmNvbYIaYW5kcm9pZC5jbGllbnRzLmdvb2dsZS5jb22CC2FuZHJvaWQuY29tghtkZXZlbG9wZXIuYW5kcm9pZC5nb29nbGUuY26CBGcuY2+CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22CEmdvb2dsZWNvbW1lcmNlLmNvbYIKdXJjaGluLmNvbYIKd3d3Lmdvby5nbIIIeW91dHUuYmWCC3lvdXR1YmUuY29tghR5b3V0dWJlZWR1Y2F0aW9uLmNvbTALBgNVHQ8EBAMCB4AwaAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBThPf/3oDfxFM/hdOi5kLv8qrZbsjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFATAIBgZngQwBAgIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAWZQy0Kvn9cPnIh7Z4kfUCXX/dhdvjLJYFAn3b3d5DVs1BLYuukfIjilVdAeTUHZH7TLn/uVejg3yS0ssRg1ds1iv2O9DJbnl5FHcjNAvwfN533FulWP41OC6B6dC6BGGTXTvQobDup7/EKg1GWX9ksBtTfKLH5wrjhN955Itnd25Sjw2bSjLaWEtTrjINXmnBoc2+qHFzF/fNxK1KbmkBboUIGoaGsThe3AF0Ye+XAeaZH08+GdrorknlHDQLLtHIcJ3C6PrQ/kTpwWd/TVXW42BN+N7xZiGJbvKOg0S0rk2hzhgX4QoUKZHMqqh1sS6ypkfnWx75nh325y4Tenk+A==";
byte encodedCert[] = Base64.getDecoder().decode(certB64);
ByteArrayInputStream inputStream = new ByteArrayInputStream(encodedCert);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(inputStream);
I assume that your certificate does not have the tags ----- BEGIN CERTIFICATE -----
and ----- END CERTIFICATE -----
EDITED
You can load directly a .cer
file encoded in base64 PEM (with -----BEGIN CERTIFICATE-----
tags).
FileInputStream inputStream = new FileInputStream (pathToYourCert);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(inputStream);
来源:https://stackoverflow.com/questions/41441276/java-how-to-decode-a-base64-encoded-certificate