在java中将x509证书写入PEM格式的字符串?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3313020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Write x509 certificate into PEM formatted string in java?
提问by pizzathehut
Is there some high level way to write an X509Certificate into a PEM formatted string? Currently I'm doing x509cert.encode() to write it into a DER formatted string, then base 64 encoding it and appending the header and footer to create a PEM string, but it seems bad. Especially since I have to throw in line breaks too.
是否有一些高级方法可以将 X509Certificate 写入 PEM 格式的字符串?目前我正在执行 x509cert.encode() 将其写入 DER 格式的字符串,然后对其进行 base 64 编码并附加页眉和页脚以创建 PEM 字符串,但这似乎很糟糕。特别是因为我也必须换行。
采纳答案by ZZ Coder
This is not bad. Java doesn't provide any functions to write PEM files. What you are doing is the correct way. Even KeyTool does the same thing,
这还不错。Java 不提供任何编写 PEM 文件的函数。你正在做的是正确的方法。甚至 KeyTool 也做同样的事情,
BASE64Encoder encoder = new BASE64Encoder();
out.println(X509Factory.BEGIN_CERT);
encoder.encodeBuffer(cert.getEncoded(), out);
out.println(X509Factory.END_CERT);
If you use BouncyCastle, you can use PEMWriter class to write out X509 certificate in PEM.
如果使用 BouncyCastle,则可以使用 PEMWriter 类在 PEM 中写出 X509 证书。
回答by judoman
To build on ZZ Coder's idea, but without using the sun.misc
classes that aren't guaranteed to be consistent between JRE versions, consider this
要以 ZZ Coder 的想法为基础,但不使用sun.misc
不能保证在 JRE 版本之间保持一致的类,请考虑这一点
Use Class:
使用等级:
import javax.xml.bind.DatatypeConverter;
Code:
代码:
try {
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(DatatypeConverter.printBase64Binary(x509cert.getEncoded()));
System.out.println("-----END CERTIFICATE-----");
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
回答by kthomeer
Previous answer gives compatibility problems with 3de party software (like PHP), because PEM cert is not correctly chunked.
先前的答案给出了与 3de 方软件(如 PHP)的兼容性问题,因为 PEM 证书未正确分块。
Imports:
进口:
import org.apache.commons.codec.binary.Base64;
Code:
代码:
protected static String convertToPem(X509Certificate cert) throws CertificateEncodingException {
Base64 encoder = new Base64(64);
String cert_begin = "-----BEGIN CERTIFICATE-----\n";
String end_cert = "-----END CERTIFICATE-----";
byte[] derCert = cert.getEncoded();
String pemCertPre = new String(encoder.encode(derCert));
String pemCert = cert_begin + pemCertPre + end_cert;
return pemCert;
}
回答by Balaji Boggaram Ramanarayan
If you have PEMWriter from bouncy castle, then you can do the following :
如果您有来自充气城堡的 PEMWriter,那么您可以执行以下操作:
Imports :
进口:
import org.bouncycastle.openssl.PEMWriter;
Code :
代码 :
/**
* Converts a {@link X509Certificate} instance into a Base-64 encoded string (PEM format).
*
* @param x509Cert A X509 Certificate instance
* @return PEM formatted String
* @throws CertificateEncodingException
*/
public String convertToBase64PEMString(Certificate x509Cert) throws IOException {
StringWriter sw = new StringWriter();
try (PEMWriter pw = new PEMWriter(sw)) {
pw.writeObject(x509Cert);
}
return sw.toString();
}
回答by jtbr
The following uses no big external libraries or possibly version-inconsistent sun.* libraries. It builds on judoman's answer, but it also chunks lines at 64 characters, as required by OpenSSL, Java, and others.
以下不使用大型外部库或可能版本不一致的 sun.* 库。它建立在 judoman 的答案之上,但它也按照 OpenSSL、Java 和其他人的要求,将行分成 64 个字符。
Import:
进口:
import javax.xml.bind.DatatypeConverter;
import java.security.cert.X509Certificate;
import java.io.StringWriter;
Code:
代码:
public static String certToString(X509Certificate cert) {
StringWriter sw = new StringWriter();
try {
sw.write("-----BEGIN CERTIFICATE-----\n");
sw.write(DatatypeConverter.printBase64Binary(cert.getEncoded()).replaceAll("(.{64})", "\n"));
sw.write("\n-----END CERTIFICATE-----\n");
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
return sw.toString();
}
(I would have just commented on judoman's answer, but I don't have enough reputation points to be allowed to comment, and my simple edit was rejected because it should have been a comment or an answer, so here's the answer.)
(我本来会评论 judoman 的答案,但我没有足够的声望点来评论,我的简单编辑被拒绝了,因为它应该是评论或答案,所以这里是答案。)
If you want to write straight to file, also import java.io.FileWriter
and:
如果您想直接写入文件,还可以import java.io.FileWriter
:
FileWriter fw = new FileWriter(certFilePath);
fw.write(certToString(myCert));
fw.close();
回答by josh-cain
Haven't seen anyone bring up Java 8's Base64.getMimeEncoder
method yet - actually allows you to specify both the line length andline separator like so:
还没有看到有人提出 Java 8 的Base64.getMimeEncoder
方法 - 实际上允许您指定行长度和行分隔符,如下所示:
final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());
I looked to see if there was any difference with this ^ vs the standard encoder, and I couldn't find anything. The javadoccites RFC 2045for both BASIC and MIME encoders, with the addition of RFC 4648for BASIC. AFAIK both of these standards use the same Base64 alphabet (tables look the same), so you should fine to use MIME if you need to specify a line length.
我查看了这个 ^ 与标准编码器是否有任何区别,但我找不到任何东西。该javadoc的引用RFC 2045的基本和MIME编码器,增加的RFC 4648的BASIC。AFAIK 这两个标准都使用相同的 Base64 字母表(表格看起来相同),因此如果您需要指定行长,您应该可以使用 MIME。
This means that with Java 8, this can be accomplished with:
这意味着在 Java 8 中,这可以通过以下方式完成:
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.util.Base64;
...
...
public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
public static final String END_CERT = "-----END CERTIFICATE-----";
public final static String LINE_SEPARATOR = System.getProperty("line.separator");
...
...
public static String formatCrtFileContents(final Certificate certificate) throws CertificateEncodingException {
final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());
final byte[] rawCrtText = certificate.getEncoded();
final String encodedCertText = new String(encoder.encode(rawCrtText));
final String prettified_cert = BEGIN_CERT + LINE_SEPARATOR + encodedCertText + LINE_SEPARATOR + END_CERT;
return prettified_cert;
}
回答by Ahmad Abdelghany
Yet another alternative for encoding using Guava's BaseEncoding:
使用Guava 的 BaseEncoding进行编码的另一种选择:
import com.google.common.io.BaseEncoding;
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final int LINE_LENGTH = 64;
And then:
进而:
String encodedCertText = BaseEncoding.base64()
.withSeparator(LINE_SEPARATOR, LINE_LENGTH)
.encode(cert.getEncoded());
回答by Andy Brown
In BouncyCastle 1.60 PEMWriter
has been deprecated in favour of PemWriter
.
在 BouncyCastle 1.60PEMWriter
中,已弃用PemWriter
.
StringWriter sw = new StringWriter();
try (PemWriter pw = new PemWriter(sw)) {
PemObjectGenerator gen = new JcaMiscPEMGenerator(cert);
pw.writeObject(gen);
}
return sw.toString();
PemWriter
is buffered so you do need to flush/close it before accessing the writer that it was constructed with.
PemWriter
已缓冲,因此您确实需要在访问构建它的编写器之前刷新/关闭它。
回答by silverduck
Almost the same as @Andy Brownone less line of code.
几乎和@Andy Brown 一样少了一行代码。
StringWriter sw = new StringWriter();
try (JcaPEMWriter jpw = new JcaPEMWriter(sw)) {
jpw.writeObject(cert);
}
String pem = sw.toString();
As he said PEMWriter is deprecated.
正如他所说,PEMWriter 已被弃用。