Today, when I was doing something about SHA256withRSA encryption, decryption and signature verification, I encountered four errors. In fact, they are all one problem, that is, this line of code reports an error :
X509Certificate cert = (X509Certificate)cf.generateCertificate(stream);
The following is the error message:
- java.io.IOException: Short read of DER length
- java.io.IOException: Incomplete BER/DER data
- readOneBlock(InputStream is) reads as null
- Could not parse certificate: java.io.IOException: Empty input
How to solve it?
The main class of the above code:
package cn.net.cdsz.svc.ttsc.asset.infrastructure.common.util.external;
import java.io.*;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
public class Sha256Utils {
public static void main(String[] args) {
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIPIEGcWBYO7j60vyjYCIVDtrlWLJ7QnuU3cG1zCjEAsBkoRvXjjw+oMHzcU4hyswuiQMA4Zj5dmfZxjErs73oPifXdhRlk7WzGIAlmXhbhwXNjl8ONrnhKpLQviOsIh+7UpMnQQxgX62eF07n/u5Sg2q3Q+Y93Qt4BBTZn736XVAgMBAAECgYA9N3bHLGerZjm8DfM1W4/2dDMD8fyjp8Bg9tqPIKDePpU9WzhVLBkaZD8r6zuOboKsXi60nhMiFa5MM4nECG+40UPQQNIcyOXXUFjQCa63loNZuAFLINnakaLrYsm9CLcVoFnqHeycZCHZAxl/kzAm46qrBMVOQ65kIq4u+XBkEQJBAMO7N7HrWjOO9KhhjlieO/f9p3TEXifBUNkX08/yiNA/N5FRFo1uv/vzaGBzUVLJKZIocroTFbDyuA/2vYLqkRcCQQCsW+quw4WdUbxEOxxJTt8DD1/DfQSGHbZQUphjoxMwiXq9L51JkNaFdQtaWs1dHMA3c8ezvSncUu1idhg++ZvzAkBGHm3HaV75FX+ESt6p1JX7M32oESkB6PlDrIuO9X4ZzGvlvTztEf3pDrwXwXgixjoESEVBb9DXgTx7S5N8sPelAkArj1NhdbKoDsco61N7x34fNNx7+HWTO6Ee7bDrxYQNCUHG3GjA9eTxd6I15KrwNFrz6MP4zf7tWtv5vWTlTYo3AkEAnd/9kxXdg5uQNTnCWZpMcwADJACOOLrJJ3YTLguMNoXYiwLSr24zaMwz5irdaWVPAvi8roRCZjE6o1mfb0SNww==";
String publiceKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDyBBnFgWDu4+tL8o2AiFQ7a5Viye0J7lN3BtcwoxALAZKEb1448PqDB83FOIcrMLokDAOGY+XZn2cYxK7O96D4n13YUZZO1sxiAJZl4W4cFzY5fDja54SqS0L4jrCIfu1KTJ0EMYF+tnhdO5/7uUoNqt0PmPd0LeAQU2Z+9+l1QIDAQAB";
String content = "哈哈!!";
String sign = rsa256Sign(content, privateKey);
System.out.println(sign);
boolean b = rsa256CheckSign(content, sign, publiceKey);
System.out.println(b);
}
/**
* 这个是签名方法
* @param content
* @param privateKey
* @return
*/
public static String rsa256Sign(String content, String privateKey) {
try {
String charset = "UTF-8";
PrivateKey priKey = KeyReader.getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));
if (priKey != null) {
java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(charset));
byte[] signed = signature.sign();
//return new String(Base64.encodeBase64(signed));
return Base64.getEncoder().encodeToString(signed);
} else {
return null;
}
} catch (Exception e) {
throw new RuntimeException("sha256WithRsa签名,出现异常!");
//return null;
}
}
/**
* 这个是验签方法
* @param content
* @param sign
* @param publicKey
* @return
*/
public static boolean rsa256CheckSign(String content, String sign, String publicKey) {
try {
sign = sign.replaceAll(" ", "+");
String charset = "UTF-8";
PublicKey pubKey = KeyReader.getPublicKeyFromX509("RSA",new ByteArrayInputStream(publicKey.getBytes()));
java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes(charset));
boolean result=signature.verify(Base64.getDecoder().decode(sign.getBytes()));
//boolean result=signature.verify(Base64.decodeBase64(sign.getBytes()));
// LOG.info("验签content"+content);
// LOG.info("验签sign"+sign);
// LOG.info("验签result"+result);
return result;
} catch (Exception e) {
// LOG.error("sha256WithRsa校验签名,出现异常", e);
throw new RuntimeException( "sha256WithRsa校验签名,出现异常!");
// return false;
}
}
}
Here are two tool helper classes: KeyReader and StreamUtil
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import jodd.util.StringUtil;
import org.apache.commons.codec.binary.Base64;
/**
* 密钥读取工具
* @author stone.zhangjl
* @version $Id: KeyReader.java, v 0.1 2008-8-21 下午04:59:42 stone.zhangjl Exp $
*/
public class KeyReader {
/**
* 将X509格式的输入流转换成Certificate对象。
*
* @param ins
* @return
* @throws
*/
public static Certificate getCertificateFromX509(InputStream ins) throws Exception {
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(ins);
return certificate;
}
/**
* @param algorithm
* @param ins
* @return
* @throws NoSuchAlgorithmException
* @throws
*/
public static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins)
throws NoSuchAlgorithmException,
Exception {
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
StringWriter writer = new StringWriter();
StreamUtil.io(new InputStreamReader(ins), writer);
byte[] encodedKey = writer.toString().getBytes();
// 先base64解码
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
}
/**
* @param algorithm
* @param ins
* @return
* @throws NoSuchAlgorithmException
* @throws
*/
public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins)
throws NoSuchAlgorithmException,
Exception {
if (ins == null || StringUtil.isBlank(algorithm)) {
return null;
}
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
byte[] encodedKey = StreamUtil.readText(ins).getBytes();
// 先base64解码
encodedKey = Base64.decodeBase64(encodedKey);
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
/**
* 基于流的工具类
*
* @author stone.zhangjl
* @version $Id: StreamUtil.java, v 0.1 2008-8-21 下午05:05:07 stone.zhangjl Exp $
*/
public class StreamUtil {
private static final int DEFAULT_BUFFER_SIZE = 8192;
/**
* 从输入流读取内容, 写入到输出流中. 此方法使用大小为8192字节的默认的缓冲区.
*
* @param in 输入流
* @param out 输出流
*
* @throws IOException 输入输出异常
*/
public static void io(InputStream in, OutputStream out) throws IOException {
io(in, out, -1);
}
/**
* 从输入流读取内容, 写入到输出流中. 使用指定大小的缓冲区.
*
* @param in 输入流
* @param out 输出流
* @param bufferSize 缓冲区大小(字节数)
*
* @throws IOException 输入输出异常
*/
public static void io(InputStream in, OutputStream out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = DEFAULT_BUFFER_SIZE;
}
byte[] buffer = new byte[bufferSize];
int amount;
while ((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}
/**
* 从输入流读取内容, 写入到输出流中. 此方法使用大小为4096字符的默认的缓冲区.
*
* @param in 输入流
* @param out 输出流
*
* @throws IOException 输入输出异常
*/
public static void io(Reader in, Writer out) throws IOException {
io(in, out, -1);
}
/**
* 从输入流读取内容, 写入到输出流中. 使用指定大小的缓冲区.
*
* @param in 输入流
* @param out 输出流
* @param bufferSize 缓冲区大小(字符数)
*
* @throws IOException 输入输出异常
*/
public static void io(Reader in, Writer out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = DEFAULT_BUFFER_SIZE >> 1;
}
char[] buffer = new char[bufferSize];
int amount;
while ((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}
/**
* 取得同步化的输出流.
*
* @param out 要包裹的输出流
*
* @return 线程安全的同步化输出流
*/
public static OutputStream synchronizedOutputStream(OutputStream out) {
return new SynchronizedOutputStream(out);
}
/**
* 取得同步化的输出流.
*
* @param out 要包裹的输出流
* @param lock 同步锁
*
* @return 线程安全的同步化输出流
*/
public static OutputStream synchronizedOutputStream(OutputStream out, Object lock) {
return new SynchronizedOutputStream(out, lock);
}
/**
* 将指定输入流的所有文本全部读出到一个字符串中.
*
* @param in 要读取的输入流
*
* @return 从输入流中取得的文本
*
* @throws IOException 输入输出异常
*/
public static String readText(InputStream in) throws IOException {
return readText(in, null, -1);
}
/**
* 将指定输入流的所有文本全部读出到一个字符串中.
*
* @param in 要读取的输入流
* @param encoding 文本编码方式
*
* @return 从输入流中取得的文本
*
* @throws IOException 输入输出异常
*/
public static String readText(InputStream in, String encoding) throws IOException {
return readText(in, encoding, -1);
}
/**
* 将指定输入流的所有文本全部读出到一个字符串中.
*
* @param in 要读取的输入流
* @param encoding 文本编码方式
* @param bufferSize 缓冲区大小(字符数)
*
* @return 从输入流中取得的文本
*
* @throws IOException 输入输出异常
*/
public static String readText(InputStream in, String encoding, int bufferSize)
throws IOException {
Reader reader = (encoding == null) ? new InputStreamReader(in) : new InputStreamReader(in,
encoding);
return readText(reader, bufferSize);
}
/**
* 将指定<code>Reader</code>的所有文本全部读出到一个字符串中.
*
* @param reader 要读取的<code>Reader</code>
*
* @return 从<code>Reader</code>中取得的文本
*
* @throws IOException 输入输出异常
*/
public static String readText(Reader reader) throws IOException {
return readText(reader, -1);
}
/**
* 将指定<code>Reader</code>的所有文本全部读出到一个字符串中.
*
* @param reader 要读取的<code>Reader</code>
* @param bufferSize 缓冲区的大小(字符数)
*
* @return 从<code>Reader</code>中取得的文本
*
* @throws IOException 输入输出异常
*/
public static String readText(Reader reader, int bufferSize) throws IOException {
StringWriter writer = new StringWriter();
io(reader, writer, bufferSize);
return writer.toString();
}
/**
* 同步化的输出流包裹器.
*/
private static class SynchronizedOutputStream extends OutputStream {
private OutputStream out;
private Object lock;
SynchronizedOutputStream(OutputStream out) {
this(out, out);
}
SynchronizedOutputStream(OutputStream out, Object lock) {
this.out = out;
this.lock = lock;
}
public void write(int datum) throws IOException {
synchronized (lock) {
out.write(datum);
}
}
public void write(byte[] data) throws IOException {
synchronized (lock) {
out.write(data);
}
}
public void write(byte[] data, int offset, int length) throws IOException {
synchronized (lock) {
out.write(data, offset, length);
}
}
public void flush() throws IOException {
synchronized (lock) {
out.flush();
}
}
public void close() throws IOException {
synchronized (lock) {
out.close();
}
}
}
}
The final running result is as follows:
(I have to sigh: Ali is really awesome!)