签名的本质其实就是加密,但是由于签名无需还原成明文,因此可以在加密前进行哈希处理。所以签名其实就是哈希+加密,而验签就是哈希+解密+比较。
签名过程:对明文做哈希,拼接头信息,用私钥进行加密,得到签名。
验签过程:用公钥解密签名,然后去除头信息,对明文做哈希,比较2段哈希值是否相同,相同则验签成功。
代码编写: Cipher 用于加密 Signature 用于签名
package com.example.tr34.application.utils;
import android.util.Base64;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
* date:2020/9/4 0004
* author:wsm (Administrator)
* funcation: 私钥有问题,base64解码失败
*/
public class RSAUtils {
private static String RSA = "RSA";
/**
* **
* RSA最大加密大小
*/
private final static int MAX_ENCRYPT_BLOCK = 117;
/**
* **
* RSA最大解密大小
*/
private final static int MAX_DECRYPT_BLOCK = 128;
/**
* 随机生成RSA密钥对(默认密钥长度为1024)
*
* @return
*/
public static KeyPair generateRSAKeyPair() {
return generateRSAKeyPair(1024);
}
/**
* 随机生成RSA密钥对
*
* @param keyLength 密钥长度,范围:512~2048
* 一般1024
* @return
*/
public static KeyPair generateRSAKeyPair(int keyLength) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
kpg.initialize(keyLength);
return kpg.genKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 用公钥加密
* 每次加密的字节数,不能超过密钥的长度值减去11
*
* @param data 需加密数据的byte数据
* @param publicKey 公钥
* @return 加密后的byte型数据
*/
public static byte[] encryptData(byte[] data, PublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// 编码前设定编码方式及密钥
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 传入编码数据并返回编码结果
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 用私钥解密
*
* @param encryptedData 经过encryptedData()加密返回的byte数据
* @param privateKey 私钥
* @return
*/
public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedData);
} catch (Exception e) {
return null;
}
}
/**
* 通过公钥byte[](publicKey.getEncoded())将公钥还原,适用于RSA算法
*
* @param keyBytes
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException,
InvalidKeySpecException {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
/**
* 通过私钥byte[]将公钥还原,适用于RSA算法
*
* @param keyBytes
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException,
InvalidKeySpecException {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
/**
* 使用N、e值还原公钥
*
* @param modulus
* @param publicExponent
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PublicKey getPublicKey(String modulus, String publicExponent)
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus);
BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
/**
* 使用N、d值还原私钥
*
* @param modulus
* @param privateExponent
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PrivateKey getPrivateKey(String modulus, String privateExponent)
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus);
BigInteger bigIntPrivateExponent = new BigInteger(privateExponent);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr 公钥数据字符串
* @throws Exception 加载公钥时产生的异常
*/
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
try {
byte[] buffer = Base64.decode(publicKeyStr,Base64.DEFAULT);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("公钥非法");
} catch (NullPointerException e) {
throw new Exception("公钥数据为空");
}
}
/**
* 从字符串中加载私钥
* 加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。
*
* @param privateKeyStr
* @return
* @throws Exception
*/
public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
try {
byte[] buffer = Base64.decode(privateKeyStr,Base64.DEFAULT);
// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
/**
* 用公钥分段加密
* 每次加密的字节数,不能超过密钥的长度值减去11
*
* @param data 需加密数据的byte数据
* @param publicKey 公钥
* @return 加密后的byte型数据
*/
public static byte[] PublicSubData(byte[] data, PublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// 编码前设定编码方式及密钥
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 传入编码数据并返回编码结果
// return cipher.doFinal(data);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0)
{
if (inputLen - offSet > MAX_ENCRYPT_BLOCK)
{
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else
{
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 用私钥分段解密
*
* @param encryptedData 经过encryptedData()加密返回的byte数据
* @param privateKey 私钥
* @return
*/
public static byte[] PrivateSubData(byte[] encryptedData, PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// return cipher.doFinal(encryptedData);
// 返回UTF-8编码的解密信息
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0)
{
if (inputLen - offSet > MAX_DECRYPT_BLOCK)
{
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else
{
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (Exception e) {
return null;
}
}
/**
* 从文件中输入流中加载公钥
*
* @param in 公钥输入流
* @throws Exception 加载公钥时产生的异常
*/
public static PublicKey loadPublicKey(InputStream in) throws Exception {
try {
return loadPublicKey(readKey(in));
} catch (IOException e) {
throw new Exception("公钥数据流读取错误");
} catch (NullPointerException e) {
throw new Exception("公钥输入流为空");
}
}
/**
* 从文件中加载私钥
*
* @param in 私钥文件名
* @return 是否成功
* @throws Exception
*/
public static PrivateKey loadPrivateKey(InputStream in) throws Exception {
try {
return loadPrivateKey(readKey(in));
} catch (IOException e) {
throw new Exception("私钥数据读取错误");
} catch (NullPointerException e) {
throw new Exception("私钥输入流为空");
}
}
/**
* 读取密钥信息
*
* @param in
* @return
* @throws IOException
*/
private static String readKey(InputStream in) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
return sb.toString();
}
/**
* 打印公钥信息
*
* @param publicKey
*/
public static void printPublicKeyInfo(PublicKey publicKey) {
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
System.out.println("----------RSAPublicKey----------");
System.out.println("Modulus.length=" + rsaPublicKey.getModulus().bitLength());
System.out.println("Modulus=" + rsaPublicKey.getModulus().toString());
System.out.println("PublicExponent.length=" + rsaPublicKey.getPublicExponent().bitLength());
System.out.println("PublicExponent=" + rsaPublicKey.getPublicExponent().toString());
}
public static void printPrivateKeyInfo(PrivateKey privateKey) {
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
System.out.println("----------RSAPrivateKey ----------");
System.out.println("Modulus.length=" + rsaPrivateKey.getModulus().bitLength());
System.out.println("Modulus=" + rsaPrivateKey.getModulus().toString());
System.out.println("PrivateExponent.length=" + rsaPrivateKey.getPrivateExponent().bitLength());
System.out.println("PrivatecExponent=" + rsaPrivateKey.getPrivateExponent().toString());
}
}
//创建X509工厂类
CertificateFactory cf = CertificateFactory.getInstance("X.509");
//创建证书对象
X509Certificate oCert = (X509Certificate)cf.generateCertificate(inStream);// inStream证书的传入数据
inStream.close();
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");
String info = null;
//获得证书版本
info = String.valueOf(oCert.getVersion());
System.out.println("证书版本:"+info);
//获得证书序列号
info = oCert.getSerialNumber().toString(16);
System.out.println("证书序列号:"+info);
//获得证书有效期
Date beforedate = oCert.getNotBefore();
info = dateformat.format(beforedate);
System.out.println("证书生效日期:"+info);
Date afterdate = oCert.getNotAfter();
info = dateformat.format(afterdate);
System.out.println("证书失效日期:"+info);
//获得证书主体信息
info = oCert.getSubjectDN().getName();
System.out.println("证书拥有者:"+info);
//获得证书颁发者信息
info = oCert.getIssuerDN().getName();
System.out.println("证书颁发者:"+info);
//获得证书签名算法名称
info = oCert.getSigAlgName();
System.out.println("证书签名算法:"+info);
byte[] byt = oCert.getExtensionValue("1.2.86.11.7.9");
String strExt = new String(byt);
System.out.println("证书扩展域:" + strExt);
byt = oCert.getExtensionValue("1.2.86.11.7.1.8");
String strExt2 = new String(byt);
System.out.println("证书扩展域2:" + strExt2);
通过X509Certificate.getPublicKey 获取公钥
/**
* Gets the key length of supported keys
* @param pk PublicKey used to derive the keysize
* @return -1 if key is unsupported, otherwise a number >= 0. 0 usually means the length can not be calculated,
* for example if the key is an EC key and the "implicitlyCA" encoding is used.
*/
public static int getKeyLength(final PublicKey pk) {
int len = -1;
if (pk instanceof RSAPublicKey) {
final RSAPublicKey rsapub = (RSAPublicKey) pk;
len = rsapub.getModulus().bitLength();
} else if (pk instanceof JCEECPublicKey) {
final JCEECPublicKey ecpriv = (JCEECPublicKey) pk;
final org.bouncycastle.jce.spec.ECParameterSpec spec = ecpriv.getParameters();
if (spec != null) {
len = spec.getN().bitLength();
} else {
// We support the key, but we don't know the key length
len = 0;
}
} else if (pk instanceof ECPublicKey) {
final ECPublicKey ecpriv = (ECPublicKey) pk;
final java.security.spec.ECParameterSpec spec = ecpriv.getParams();
if (spec != null) {
len = spec.getOrder().bitLength(); // does this really return something we expect?
} else {
// We support the key, but we don't know the key length
len = 0;
}
} else if (pk instanceof DSAPublicKey) {
final DSAPublicKey dsapub = (DSAPublicKey) pk;
if ( dsapub.getParams() != null ) {
len = dsapub.getParams().getP().bitLength();
} else {
len = dsapub.getY().bitLength();
}
}
return len;
}