Java-如何解码Base64编码的证书(Java - How to decode a Base64 encoded Certificate)

30 IT屋

Below is my requirement:

  1. Program will have an xml file as input with 3 tags: , and . All these data are Base64 encoded. Note: Program is using BC jars
  2. Program needs to decode them and verify the data for its authenticity using the signature and certificate
  3. 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-----

解决方案

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);

以下是我的要求:




  1. 程序将有一个xml文件作为输入,带有3个标记:和。所有这些数据都是Base64编码的。注意:程序正在使用BC jars

  2. 程序需要对其进行解码,并使用签名和证书来验证数据的真实性

  3. 验证后的数据应为Base64解码并写入另一个文件




下面是我的试图对证书进行解码的代码:




  public void executeTask(InputStream arg0,OutputStream arg1)抛出SomeException {
try {
BufferedReader br = null;
br = new BufferedReader(new InputStreamReader(arg0));
字符串orgContent ="",splitData ="",signContent ="",certContent ="";

DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
文档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签名= doc.getElementsByTagName(" Signature");
元素signatureElement =(Element)signature.item(0);
NodeList signatureContent = signatureElement.getChildNodes();
signContent =(((Node)signatureContent.item(0))。getNodeValue()。trim();

NodeList证书= doc.getElementsByTagName(" Certificate");
元素certificateElement =(Element)certificate.item(0);
NodeList certificateContent = certificateElement.getChildNodes();
certContent =(((Node)certificateContent.item(0))。getNodeValue()。trim();
字符串解码的证书内容=新的字符串(Base64.decode(certContent),StandardCharsets.UTF_8);
byte [] certByteValue = Base64.decode(certContent);
CertificateFactory certFactory = CertificateFactory.getInstance(" X.509");
System.out.println(" certContent:\n" +新的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();
}


}



当我打印新String(certByteValue,StandardCharsets.UTF_8)的值时,程序正在打印一些无法识别的文本。当执行代码的最后一行 X509Certificate cert =(X509Certificate)certFactory.generateCertificate(inputStream); 系统抛出java.security.cert.CertificateException:无法解析证书: java.io.IOException:无效的BER / DER数据(太大吗?)。



由于我是这些Certificates的新手,所以遇到了僵局。我无法继续执行该要求。我想知道如何实现上述要求。



编辑
上面代码的输入流将是xml文件。另一个程序使用带有签名和证书的base64编码数据创建该xml文件。在该程序中,使用以下代码对证书进行编码:



  KeyStore keyStore = KeyStore.getInstance(" JKS"); 
keyStore.load(new FileInputStream(" Filepath / certificate.p12")," password" .toCharArray());
PrivateKey privateKey =(PrivateKey)keyStore.getKey(alias," password" .toCharArray());

CertificateFactory工厂= CertificateFactory.getInstance(" X.509");
X509Certificate证书=(X509Certificate)factory.generateCertificate(new FileInputStream(" D:/ Sujai / Implementation Team / PI / Axis Treds / Certificates / PI_7.5_Cert / Arteria_Certificate-cert.cert"));
byte [] encodeCert = certificate.getEncoded();
String encodingStringCert =新的String(Base64.encode(新的String(encodedCert).getBytes(StandardCharsets.UTF_8)));


变量 encodedStringCert 作为标签内的证书值传递。在此问题顶部共享的程序中,我需要对该证书值进行解码。



示例证书内容:----- BEGIN证书- ---
MIIDBjCCAe6 .... IM1g ==
-----结束证书-----


解决方案

新字符串(certByteValue,StandardCharsets.UTF_8)失败,因为证书编码数据无法表示为字符串



问题可能是源数据不是base64 X509证书,或者库 Base64.decode()的编码问题。我建议使用Java 8的标准解码器 Base64.getDecoder()。decode()或 DataTypeConverter.parseBase64Binary()对于Java> 6



还要检查此工作代码以解码base64编码的证书



 字符串certB64 ="MIIHFDCCBfygAwIBAgIIK2o4sL7KHQgwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTYxMjE1MTQwNDE1WhcNMTcwMzA5MTMzNTAwWjBmMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEVMBMGA1UEAwwMKi5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEG1y99TYpFSSiawnjJKYI8hyEzJ4M + IELfLjmSsYI7fW / V8AT61quCswtBMikJYqzYBZrV2Reu5sHlLr6936cR6OCBKwwggSoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCCA2sGA1UdEQSCA2IwggNeggwqLmdvb2dsZS5jb22CDSouYW5kcm9pZC5jb22CFiouYXBwZW5naW5lLmdvb2dsZS5jb22CEiouY2xvdWQuZ29vZ2xlLmNvbYIWKi5nb29nbGUtYW5hbHl0aWNzLmNvbYILKi5nb29nbGUuY2GCCyouZ29vZ2xlLmNsgg4qLmdvb2dsZS5jby5pboIO Ki5nb29nbGUuY28uanCCDiouZ29vZ2xlLmNvLnVrgg8qLmdvb2dsZS5jb20uYXKCDyouZ29vZ2xlLmNvbS5hdYIPKi5nb29nbGUuY29tLmJygg8qLmdvb2dsZS5jb20uY2 + CDyouZ29vZ2xlLmNvbS5teIIPKi5nb29nbGUuY29tLnRygg8qLmdvb2dsZS5jb20udm6CCyouZ29vZ2xlLmRlggsqLmdvb2dsZS5lc4ILKi5nb29nbGUuZnKCCyouZ29vZ2xlLmh1ggsqLmdvb2dsZS5pdIILKi5nb29nbGUubmyCCyouZ29vZ2xlLnBsggsqLmdvb2dsZS5wdIISKi5nb29nbGVhZGFwaXMuY29tgg8qLmdvb2dsZWFwaXMuY26CFCouZ29vZ2xlY29tbWVyY2UuY29tghEqLmdvb2dsZXZpZGVvLmNvbYIMKi5nc3RhdGljLmNugg0qLmdzdGF0aWMuY29tggoqLmd2dDEuY29tggoqLmd2dDIuY29tghQqLm1ldHJpYy5nc3RhdGljLmNvbYIMKi51cmNoaW4uY29tghAqLnVybC5nb29nbGUuY29tghYqLnlvdXR1YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYqLnlvdXR1YmVlZHVjYXRpb24uY29tggsqLnl0aW1nLmNvbYIaYW5kcm9pZC5jbGllbnRzLmdvb2dsZS5jb22CC2FuZHJvaWQuY29tghtkZXZlbG9wZXIuYW5kcm9pZC5nb29nbGUuY26CBGcuY2 + CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22CEmdvb2dsZWNvbW1lcmNlLmNvbYIKdXJjaGluLmNvbYIKd3d3Lmdvby5nbIIIeW91dHUuYmWCC3lvdXR1YmUuY29tghR5b3V0dWJlZWR1Y2F0aW9uLmNvbTALBgNVHQ8EBAMCB4AwaAYIKwYBBQUHAQEEXDBa MCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBThPf / 3oDfxFM / hdOi5kLv8qrZbsjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFATAIBgZngQwBAgIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAWZQy0Kvn9cPnIh7Z4kfUCXX / dhdvjLJYFAn3b3d5DVs1BLYuukfIjilVdAeTUHZH7TLn / uVejg3yS0ssRg1ds1iv2O9DJbnl5FHcjNAvwfN533FulWP41OC6B6dC6BGGTXTvQobDup7 / EKg1GWX9ksBtTfKLH5wrjhN955Itnd25Sjw2bSjLaWEtTrjINXmnBoc2 + qHFzF / fNxK1KbmkBboUIGoaGsThe3AF0Ye + XAeaZH08 + GdrorknlHDQLLtHIcJ3C6PrQ / kTpwWd / TVXW42BN + N7xZiGJbvKOg0S0rk2hzhgX4QoUKZHMqqh1sS6ypkfnWx75nh325y4Tenk + A =="; 
个字节encodeCert [] = Base64.getDecoder()。decode(certB64);
ByteArrayInputStream inputStream =新的ByteArrayInputStream(encodedCert);

CertificateFactory certFactory = CertificateFactory.getInstance(" X.509");
X509Certificate cert =(X509Certificate)certFactory.generateCertificate(inputStream);


我假设您的证书没有标签 -----开始证书----- 和 -----结束证书-----



已编辑



您可以直接加载编码后的 .cer 文件在base64 PEM中(带有 ----- BEGIN CERTIFICATE ----- 标签)。



  FileInputStream inputStream =新的FileInputStream(pathToYourCert); 
CertificateFactory certFactory = CertificateFactory.getInstance(" X.509");
X509Certificate cert =(X509Certificate)certFactory.generateCertificate(inputStream);

本文地址:IT屋 » Java-如何解码Base64编码的证书