本文 字数:1619
密钥位数:1024。
密钥格式:PKCS#8。
数字签名签名/验证算法:SHA1withRSA。
RSA最大加密明文大小:117
RSA最大解密密文大小:128
1、原RSA公私密钥对,转16进制公私密钥。2、自动生成16进制密钥对。3、使用16进制私钥签名。4、使用16进制公钥验证。5、使用16进制私钥进行原数据加密。6、使用16进制公钥进行解密。7、对于16进制公钥加密,16私钥解密本文不说说明,稍微改一下就可以使用。8、完整代码
需要对包
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StringUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
1、原RSA公私密钥对,转16进制公私密钥
操作:先进性Base64解码,再把byte数组转成16进制即可。
代码:
//私钥
String privateKeyString = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMjT4WYC7xFo5CRw\n" +
"dHSseOsAqZKV2Ksrjp54yysba66TbVJ9Ai1WioCsP7WBkCSnMbECfb1jfJl37km2\n" +
"moMMrhrKXNmrKhO5kEKLKZQZdg+/wVugFyzRhxEOIBbEQ6mIeyWVee4zkg+R9GIy\n" +
"gt9mGhrAhBqqO1lZaAn5/iF43seLAgMBAAECgYAWRlH4w5iKoMy1MffovPyIbEFi\n" +
"rdYjXihqcVFvjZILAfUdMhpctv2Tugcy9ZTsS9MaJAGYUQGP8Bpw+Jz4rh5dTebx\n" +
"c8cqZ9NhI9h0gceGYJPyvtw7KdUnFRkYnlcj3vOwR9x793nJl1Yo0APCYl4jk7he\n" +
"sm4YcCGY52uF7dQGuQJBAPQpRp5VJYuLXzsNNVkxIb27gpfTJVaYZoto2FqlpYhV\n" +
"USRKGuTP+/5BZjJOBTRMaJvDqy15Ev/PrIm+8+5mvxUCQQDSkLazWyzVPfFAWO7I\n" +
"3ICv/REtNdXkFQ6FYtYLzgusxFaNr75RsJsgeXfSQxD9RmPb2ipKeY3ertU25ZIl\n" +
"gBQfAkBURKat4N9LcTfV7rIZ7X4iuMPS2LoLUCAcP3xklMUz75ZIuxbbH/luAG5g\n" +
"MFNVgIWeNQMwd5gaGDgJdpFEF8wdAkAYkOWf2z1Jy6Y/2aBSMteYsK+2VJeVupct\n" +
"HLDYQ7u89lMayKwtn6sZiNJf548t3W59EeDpO3E/z6n0c6gvU9gFAkBRxq0RXi/2\n" +
"5wpEjeRd+tL30WrC2PoTVN6San5cPkv2k6vVWmZJAAMB6RKHtp+r7yUYLcEcrZOG\n" +
"7ARIDVY19ou5";
//公钥
String publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI0+FmAu8RaOQkcHR0rHjrAKmS\n" +
"ldirK46eeMsrG2uuk21SfQItVoqArD+1gZAkpzGxAn29Y3yZd+5JtpqDDK4aylzZ\n" +
"qyoTuZBCiymUGXYPv8FboBcs0YcRDiAWxEOpiHsllXnuM5IPkfRiMoLfZhoawIQa\n" +
"qjtZWWgJ+f4heN7HiwIDAQAB";
//私钥16进制
byte[] bytes1 = Base64.decodeBase64(privateKeyString);
String pri = byte2Hex(bytes1);
//私钥16进制
byte[] ddd = Base64.decodeBase64(publicKeyString);
String pub = byte2Hex(ddd);
结果:
16进制私钥:30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100c8d3e16602ef1168e424707474ac78eb00a99295d8ab2b8e9e78cb2b1b6bae936d527d022d568a80ac3fb5819024a731b1027dbd637c9977ee49b69a830cae1aca5cd9ab2a13b990428b299419760fbfc15ba0172cd187110e2016c443a9887b259579ee33920f91f4623282df661a1ac0841aaa3b59596809f9fe2178dec78b0203010001028180164651f8c3988aa0ccb531f7e8bcfc886c4162add6235e286a71516f8d920b01f51d321a5cb6fd93ba0732f594ec4bd31a24019851018ff01a70f89cf8ae1e5d4de6f173c72a67d36123d87481c7866093f2bedc3b29d5271519189e5723def3b047dc7bf779c9975628d003c2625e2393b85eb26e18702198e76b85edd406b9024100f429469e55258b8b5f3b0d35593121bdbb8297d3255698668b68d85aa5a5885551244a1ae4cffbfe4166324e05344c689bc3ab2d7912ffcfac89bef3ee66bf15024100d290b6b35b2cd53df14058eec8dc80affd112d35d5e4150e8562d60bce0bacc4568dafbe51b09b207977d24310fd4663dbda2a4a798ddeaed536e5922580141f02405444a6ade0df4b7137d5eeb219ed7e22b8c3d2d8ba0b50201c3f7c6494c533ef9648bb16db1ff96e006e6030535580859e35033077981a18380976914417cc1d02401890e59fdb3d49cba63fd9a05232d798b0afb6549795ba972d1cb0d843bbbcf6531ac8ac2d9fab1988d25fe78f2ddd6e7d11e0e93b713fcfa9f473a82f53d805024051c6ad115e2ff6e70a448de45dfad2f7d16ac2d8fa1354de926a7e5c3e4bf693abd55a6649000301e91287b69fabef25182dc11cad9386ec04480d5635f68bb9
16进制公钥:30819f300d06092a864886f70d010101050003818d0030818902818100c8d3e16602ef1168e424707474ac78eb00a99295d8ab2b8e9e78cb2b1b6bae936d527d022d568a80ac3fb5819024a731b1027dbd637c9977ee49b69a830cae1aca5cd9ab2a13b990428b299419760fbfc15ba0172cd187110e2016c443a9887b259579ee33920f91f4623282df661a1ac0841aaa3b59596809f9fe2178dec78b0203010001
涉及的方法:
Base64:
org.apache.commons.codec.binary.Base64
byte2Hex:
/**
* @param bytes,输入byte[]数组
* @return 16进制字符
* @Description: 将byte[]数组转换成16进制字符。一个byte生成两个字符,长度对应1:2
* @Author: mastermind
* @Date: 2020-04-06 12:16
*/
public static String byte2Hex(byte[] bytes) {
if (bytes == null) {
return null;
}
StringBuilder builder = new StringBuilder();
// 遍历byte[]数组,将每个byte数字转换成16进制字符,再拼接起来成字符串
for (int i = 0; i < bytes.length; i++) {
// 每个byte转换成16进制字符时,bytes[i] & 0xff如果高位是0,输出将会去掉,所以+0x100(在更高位加1),再截取后两位字符
builder.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return builder.toString();
}
扩展:
得到16进制公私密钥,可以提取出指数和系数。
2、自动生成16进制密钥对
操作:有代码直接生成
代码:
/**
* 生成1024位RSA公私钥对。
*
* @return 私钥、公钥
*/
public static String[] genRSAKeyPair() {
KeyPairGenerator rsaKeyGen = null;
KeyPair rsaKeyPair = null;
try {
log.error("Generating a pair of RSA key ... ");
rsaKeyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
random.setSeed(("" + System.currentTimeMillis() * Math.random() * Math.random()).getBytes(Charset
.forName("UTF-8")));
rsaKeyGen.initialize(1024, random);
rsaKeyPair = rsaKeyGen.genKeyPair();
PublicKey rsaPublic = rsaKeyPair.getPublic();
PrivateKey rsaPrivate = rsaKeyPair.getPrivate();
String privateAndPublic[] = new String[2];
privateAndPublic[0] = byte2Hex(rsaPrivate.getEncoded());
privateAndPublic[1] = byte2Hex(rsaPublic.getEncoded());
System.err.println("16私钥:" + privateAndPublic[0]);
System.err.println("16公钥:" + privateAndPublic[1]);
return privateAndPublic;
} catch (Exception e) {
log.error("genRSAKeyPair error:" + e.getMessage(), e);
return null;
}
}
结果:
16私钥:30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100b0fbba4081656a1cc681315dbd815ee0b198d293def06f2d8d6fb17b64542999a361ec4f7c04e4353aadbf0397169651643d7923e22f038b9b0cafd58c46cd6822ff0e22146612fd872d0b27aa3f1121cc95e144a940de10065c5b261f242f667fccfc5fd5422d82af71d7c4f900843d12949411d726d82ece8b3c8808b4da1d02030100010281807a5c2f72f583260feaf5db299221657537940ed28929f5d3aa9b743b792beeeef7d475caa655c36941be69f79377dc493d627ae462365adf243d6b3bdb1600603e4791eb1700414f189ae1b02b3b40c0093922a5888d1358aec92779546256f5a903a1bb88beacd44514bbd88b18871699a9a1944806bdb783886fcee1a6f349024100e040d5d61bfd4ae8f7b6b93cb6131a5d17dcd1a617032db1d96ee4d4982792e58697e9b67afdb7399b8d673cfb05f911099cc462c30dd932d63b8dbd2bf9e73b024100ca09c80d007e11a29fa7b5d9352c169d98d6def82c473a06687d8eb6589a371923763679c9da6458dd3d7d36bd81aace3236227aa05e86a65ac7773eed491e87024051063bfccb4a1e49c44ec9e8eca4444f4472ed70c439cac5ca98eda6fe7eb5eda64eb70bceae63083672c5cd5ba951cf5d18be402cd7911574203a5b124b8dc702406a15f0c142fcef6da0bf8330e6469c296c53870870d785944fd17dda2973f07276b85faa5b5f1d49bc01c979b0d0214bdbf9a8e912c40f97d21ae2765c4a048902400a02d95a302b6fa69b4da0f146ffdd7ecc0154d852a01023c9af11e13a03ab223ccd26f7be0bfeea4fc5b7904f19880e47c25d31d8f2c43c320b75a50211c9cd
16公钥:30819f300d06092a864886f70d010101050003818d0030818902818100b0fbba4081656a1cc681315dbd815ee0b198d293def06f2d8d6fb17b64542999a361ec4f7c04e4353aadbf0397169651643d7923e22f038b9b0cafd58c46cd6822ff0e22146612fd872d0b27aa3f1121cc95e144a940de10065c5b261f242f667fccfc5fd5422d82af71d7c4f900843d12949411d726d82ece8b3c8808b4da1d0203010001
3、使用16进制私钥签名
操作:由16进制私钥转成私钥对象,在进行签名运算
代码:
//16进制私钥
String pri = "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100c8d3e16602ef1168e424707474ac78eb00a99295d8ab2b8e9e78cb2b1b6bae936d527d022d568a80ac3fb5819024a731b1027dbd637c9977ee49b69a830cae1aca5cd9ab2a13b990428b299419760fbfc15ba0172cd187110e2016c443a9887b259579ee33920f91f4623282df661a1ac0841aaa3b59596809f9fe2178dec78b0203010001028180164651f8c3988aa0ccb531f7e8bcfc886c4162add6235e286a71516f8d920b01f51d321a5cb6fd93ba0732f594ec4bd31a24019851018ff01a70f89cf8ae1e5d4de6f173c72a67d36123d87481c7866093f2bedc3b29d5271519189e5723def3b047dc7bf779c9975628d003c2625e2393b85eb26e18702198e76b85edd406b9024100f429469e55258b8b5f3b0d35593121bdbb8297d3255698668b68d85aa5a5885551244a1ae4cffbfe4166324e05344c689bc3ab2d7912ffcfac89bef3ee66bf15024100d290b6b35b2cd53df14058eec8dc80affd112d35d5e4150e8562d60bce0bacc4568dafbe51b09b207977d24310fd4663dbda2a4a798ddeaed536e5922580141f02405444a6ade0df4b7137d5eeb219ed7e22b8c3d2d8ba0b50201c3f7c6494c533ef9648bb16db1ff96e006e6030535580859e35033077981a18380976914417cc1d02401890e59fdb3d49cba63fd9a05232d798b0afb6549795ba972d1cb0d843bbbcf6531ac8ac2d9fab1988d25fe78f2ddd6e7d11e0e93b713fcfa9f473a82f53d805024051c6ad115e2ff6e70a448de45dfad2f7d16ac2d8fa1354de926a7e5c3e4bf693abd55a6649000301e91287b69fabef25182dc11cad9386ec04480d5635f68bb9";
//原数据
String data = "123456";
System.err.println("代签名数据:" + data);
//签名
String sign = sign(getPrivateKey(pri), data, "utf-8");
System.err.println("私钥16签名:" + sign);
结果:
代签名数据:123456
私钥16签名:885d59e3ff349d7fb03903e2304556ceadfea1bf38c972575d20489e69e4b178bc7076db216a9150e7beac7b263eb967fe9129c6c1d70e127d379d0fe048531e0083fb3cd7e8415f68c91f7f1756c0e50dc98866bb9004c0db402be7f1d8e8acd5d5365bffae1259d3d347f233bebc348e9a52ac4aebaa165eac0269015fc622
涉及的方法:
getPrivateKey:
/**
* 得到私钥对象
*
* @param key 密钥字符串(经过16进制编码)
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) {
try {
byte[] keyBytes = hex2Byte(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
String info = "getPrivateKey failed: " + key + " | " + e.getMessage();
return null;
}
}
hex2Byte:
/**
* 将16进制字符转换成byte[]数组。与byte2Hex功能相反。
*
* @param string 16进制字符串
* @return byte[]数组
*/
public static byte[] hex2Byte(String string) {
if (string == null || string.length() < 1) {
return null;
}
// 因为一个byte生成两个字符,长度对应1:2,所以byte[]数组长度是字符串长度一半
byte[] bytes = new byte[string.length() / 2];
// 遍历byte[]数组,遍历次数是字符串长度一半
for (int i = 0; i < string.length() / 2; i++) {
// 截取没两个字符的前一个,将其转为int数值
int high = Integer.parseInt(string.substring(i * 2, i * 2 + 1), 16);
// 截取没两个字符的后一个,将其转为int数值
int low = Integer.parseInt(string.substring(i * 2 + 1, i * 2 + 2), 16);
// 高位字符对应的int值*16+低位的int值,强转成byte数值即可
// 如dd,高位13*16+低位13=221(强转成byte二进制11011101,对应十进制-35)
bytes[i] = (byte) (high * 16 + low);
}
return bytes;
}
sign:
/**
* 使用SHA1withRSA签名算法产生签名
*
* @param privateKey privateKey 签名时使用的私钥(16进制编码)
* @param src src 签名的原字符串
* @return String 签名的返回结果(16进制编码)。当产生签名出错的时候,返回null。
*/
public static String sign(PrivateKey privateKey, String src, String encode) {
try {
Signature sigEng = Signature.getInstance(SIGNATURE_ALGORITHM);
sigEng.initSign(privateKey);
sigEng.update(src.getBytes(encode));
byte[] signature = sigEng.sign();
return byte2Hex(signature);
} catch (Exception e) {
return null;
}
}
4、使用16进制公钥验证
操作:传入的签名,公钥都是 16进制格式
代码:
//16进制公钥
String pub = "30819f300d06092a864886f70d010101050003818d0030818902818100c8d3e16602ef1168e424707474ac78eb00a99295d8ab2b8e9e78cb2b1b6bae936d527d022d568a80ac3fb5819024a731b1027dbd637c9977ee49b69a830cae1aca5cd9ab2a13b990428b299419760fbfc15ba0172cd187110e2016c443a9887b259579ee33920f91f4623282df661a1ac0841aaa3b59596809f9fe2178dec78b0203010001";
//原数据
String data = "123456";
System.err.println("代签名数据:" + data);
//签名16进制
String sign = "885d59e3ff349d7fb03903e2304556ceadfea1bf38c972575d20489e69e4b178bc7076db216a9150e7beac7b263eb967fe9129c6c1d70e127d379d0fe048531e0083fb3cd7e8415f68c91f7f1756c0e50dc98866bb9004c0db402be7f1d8e8acd5d5365bffae1259d3d347f233bebc348e9a52ac4aebaa165eac0269015fc622";
//验证
verify(getPublicKey(pub), sign, data, "utf-8");
结果:
代签名数据:123456
验证结果:=====true=====
涉及的方法:
1、getPublicKey:/**
* 获取公钥
*
* @param publicKey 公钥字符串
* @return
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = hex2Byte(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
return keyFactory.generatePublic(keySpec);
}2、verify
/**
* 使用SHA1withRSA签名算法验证签名
*
* @param publicKey pubKey 验证签名时使用的公钥(16进制编码)
* @param sign sign 签名结果(16进制编码)
* @param src src 签名的原字符串
*/
public static void verify(PublicKey publicKey, String sign, String src, String encode) throws Exception {
try {
if (StringUtils.isEmpty(sign) || StringUtils.isEmpty(src)) {
throw new RuntimeException("sign或内容不容为空");
}
Signature sigEng = Signature.getInstance("SHA1withRSA");
sigEng.initVerify(publicKey);
sigEng.update(src.getBytes(encode));
byte[] sign1 = hex2Byte(sign);
boolean aaa = sigEng.verify(sign1);
System.out.println("验证结果:=====" + aaa + "=====");
if (!aaa) {
throw new Exception("验签失败");
}
} catch (Exception e) {
throw new Exception("验签失败");
}
}
以下部分全部放在代码中,在main中查找
全部代码
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StringUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@Slf4j
public class RSAUtil {
/**
* 数字签名,密钥算法
*/
private static final String RSA_KEY_ALGORITHM = "RSA";
/**
* 数字签名签名/验证算法
*/
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/**
* RSA密钥长度,RSA算法的默认密钥长度是1024密钥长度必须是64的倍数,在512到65536位之间
*/
private static final int KEY_SIZE = 1024;
/** */
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/** */
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* @param bytes,输入byte[]数组
* @return 16进制字符
* @Description: 将byte[]数组转换成16进制字符。一个byte生成两个字符,长度对应1:2
* @Author: mastermind
* @Date: 2020-04-06 12:16
*/
public static String byte2Hex(byte[] bytes) {
if (bytes == null) {
return null;
}
StringBuilder builder = new StringBuilder();
// 遍历byte[]数组,将每个byte数字转换成16进制字符,再拼接起来成字符串
for (int i = 0; i < bytes.length; i++) {
// 每个byte转换成16进制字符时,bytes[i] & 0xff如果高位是0,输出将会去掉,所以+0x100(在更高位加1),再截取后两位字符
builder.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return builder.toString();
}
/**
* 将16进制字符转换成byte[]数组。与byte2Hex功能相反。
*
* @param string 16进制字符串
* @return byte[]数组
*/
public static byte[] hex2Byte(String string) {
if (string == null || string.length() < 1) {
return null;
}
// 因为一个byte生成两个字符,长度对应1:2,所以byte[]数组长度是字符串长度一半
byte[] bytes = new byte[string.length() / 2];
// 遍历byte[]数组,遍历次数是字符串长度一半
for (int i = 0; i < string.length() / 2; i++) {
// 截取没两个字符的前一个,将其转为int数值
int high = Integer.parseInt(string.substring(i * 2, i * 2 + 1), 16);
// 截取没两个字符的后一个,将其转为int数值
int low = Integer.parseInt(string.substring(i * 2 + 1, i * 2 + 2), 16);
// 高位字符对应的int值*16+低位的int值,强转成byte数值即可
// 如dd,高位13*16+低位13=221(强转成byte二进制11011101,对应十进制-35)
bytes[i] = (byte) (high * 16 + low);
}
return bytes;
}
/**
* 使用SHA1withRSA签名算法产生签名
*
* @param privateKey privateKey 签名时使用的私钥(16进制编码)
* @param src src 签名的原字符串
* @return String 签名的返回结果(16进制编码)。当产生签名出错的时候,返回null。
*/
public static String sign(PrivateKey privateKey, String src, String encode) {
try {
Signature sigEng = Signature.getInstance(SIGNATURE_ALGORITHM);
sigEng.initSign(privateKey);
sigEng.update(src.getBytes(encode));
byte[] signature = sigEng.sign();
return byte2Hex(signature);
} catch (Exception e) {
String info = "sign failed: " + src + " | " + e.getMessage();
return null;
}
}
/**
* 本方法使用SHA1withRSA签名算法验证签名
*
* @param publicKey pubKey 验证签名时使用的公钥(16进制编码)
* @param sign sign 签名结果(16进制编码)
* @param src src 签名的原字符串
*/
public static void verify(PublicKey publicKey, String sign, String src, String encode) throws Exception {
try {
if (StringUtils.isEmpty(sign) || StringUtils.isEmpty(src)) {
throw new RuntimeException("sign或内容不容为空");
}
Signature sigEng = Signature.getInstance("SHA1withRSA");
sigEng.initVerify(publicKey);
sigEng.update(src.getBytes(encode));
byte[] sign1 = hex2Byte(sign);
boolean aaa = sigEng.verify(sign1);
System.out.println("验证结果:=====" + aaa + "=====");
if (!aaa) {
throw new Exception("验签失败");
}
} catch (Exception e) {
throw new Exception("验签失败");
}
}
/**
* 1024位RSA公私钥对。
*
* @return 私钥、公钥
*/
public static String[] genRSAKeyPair() {
KeyPairGenerator rsaKeyGen = null;
KeyPair rsaKeyPair = null;
try {
log.error("Generating a pair of RSA key ... ");
rsaKeyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
random.setSeed(("" + System.currentTimeMillis() * Math.random() * Math.random()).getBytes(Charset
.forName("UTF-8")));
rsaKeyGen.initialize(1024, random);
rsaKeyPair = rsaKeyGen.genKeyPair();
PublicKey rsaPublic = rsaKeyPair.getPublic();
PrivateKey rsaPrivate = rsaKeyPair.getPrivate();
String privateAndPublic[] = new String[2];
privateAndPublic[0] = byte2Hex(rsaPrivate.getEncoded());
privateAndPublic[1] = byte2Hex(rsaPublic.getEncoded());
System.err.println("16私钥:" + privateAndPublic[0]);
System.err.println("16公钥:" + privateAndPublic[1]);
return privateAndPublic;
} catch (Exception e) {
return null;
}
}
/**
* 得到私钥对象
*
* @param key 密钥字符串(经过16进制编码)
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) {
try {
byte[] keyBytes = hex2Byte(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
String info = "getPrivateKey failed: " + key + " | " + e.getMessage();
return null;
}
}
/**
* 获取公钥
*
* @param publicKey 公钥字符串
* @return
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = hex2Byte(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
return keyFactory.generatePublic(keySpec);
}
/** */
/**
* <p>
* 私钥加密
* </p>
*
* @param str 源数据
* @param privateKey 私钥(16 进制)
* @return 16进制加密数据
* @throws Exception
*/
public static String encryptByPrivateKey(String str, String privateKey) {
try {
byte[] keyBytes = hex2Byte(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateK = keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
byte[] data = str.getBytes("utf-8");
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[] encryptedData = out.toByteArray();
out.close();
//转16进制
String s = byte2Hex(encryptedData);
return s;
} catch (Exception e) {
throw new RuntimeException("私钥加密错误");
}
}
/** */
/**
* <p>
* 公钥解密
* </p>
*
* @param str 已加密数据(16进制)
* @param publicKey 公钥(16进制)
* @return 原数据
* @throws Exception
*/
public static String decryptByPublicKey(String str, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = hex2Byte(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
PublicKey publicK = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
//16进制数据转byte[]
byte[] encryptedData = hex2Byte(str);
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 new String(decryptedData);
} catch (Exception e) {
throw new RuntimeException("公钥解密错误");
}
}
public static void main(String[] args) {
//生成1024位16进制密钥
// genRSAKeyPair();
// 私钥
String privateKeyString = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMjT4WYC7xFo5CRw\n" +
"dHSseOsAqZKV2Ksrjp54yysba66TbVJ9Ai1WioCsP7WBkCSnMbECfb1jfJl37km2\n" +
"moMMrhrKXNmrKhO5kEKLKZQZdg+/wVugFyzRhxEOIBbEQ6mIeyWVee4zkg+R9GIy\n" +
"gt9mGhrAhBqqO1lZaAn5/iF43seLAgMBAAECgYAWRlH4w5iKoMy1MffovPyIbEFi\n" +
"rdYjXihqcVFvjZILAfUdMhpctv2Tugcy9ZTsS9MaJAGYUQGP8Bpw+Jz4rh5dTebx\n" +
"c8cqZ9NhI9h0gceGYJPyvtw7KdUnFRkYnlcj3vOwR9x793nJl1Yo0APCYl4jk7he\n" +
"sm4YcCGY52uF7dQGuQJBAPQpRp5VJYuLXzsNNVkxIb27gpfTJVaYZoto2FqlpYhV\n" +
"USRKGuTP+/5BZjJOBTRMaJvDqy15Ev/PrIm+8+5mvxUCQQDSkLazWyzVPfFAWO7I\n" +
"3ICv/REtNdXkFQ6FYtYLzgusxFaNr75RsJsgeXfSQxD9RmPb2ipKeY3ertU25ZIl\n" +
"gBQfAkBURKat4N9LcTfV7rIZ7X4iuMPS2LoLUCAcP3xklMUz75ZIuxbbH/luAG5g\n" +
"MFNVgIWeNQMwd5gaGDgJdpFEF8wdAkAYkOWf2z1Jy6Y/2aBSMteYsK+2VJeVupct\n" +
"HLDYQ7u89lMayKwtn6sZiNJf548t3W59EeDpO3E/z6n0c6gvU9gFAkBRxq0RXi/2\n" +
"5wpEjeRd+tL30WrC2PoTVN6San5cPkv2k6vVWmZJAAMB6RKHtp+r7yUYLcEcrZOG\n" +
"7ARIDVY19ou5";
//公钥
String publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI0+FmAu8RaOQkcHR0rHjrAKmS\n" +
"ldirK46eeMsrG2uuk21SfQItVoqArD+1gZAkpzGxAn29Y3yZd+5JtpqDDK4aylzZ\n" +
"qyoTuZBCiymUGXYPv8FboBcs0YcRDiAWxEOpiHsllXnuM5IPkfRiMoLfZhoawIQa\n" +
"qjtZWWgJ+f4heN7HiwIDAQAB";
//私钥16进制
byte[] bytes1 = Base64.decodeBase64(privateKeyString);
String pri = byte2Hex(bytes1);
//私钥16进制
byte[] ddd = Base64.decodeBase64(publicKeyString);
String pub = byte2Hex(ddd);
try {
//原数据
String data = "123456";
System.err.println("代签名数据:" + data);
//签名
String sign = sign(getPrivateKey(pri), data, "utf-8");
System.err.println("私钥16签名:" + sign);
//验证
verify(getPublicKey(pub), sign, data, "utf-8");
//私钥加密 数据转16进制
String s = encryptByPrivateKey(data, pri);
System.err.println("私钥加密:" + s);
//公钥解密
String s1 = decryptByPublicKey(s, pub);
System.err.println("公钥解密:" + s1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
main运行后结果
代签名数据:123456
私钥16签名:885d59e3ff349d7fb03903e2304556ceadfea1bf38c972575d20489e69e4b178bc7076db216a9150e7beac7b263eb967fe9129c6c1d70e127d379d0fe048531e0083fb3cd7e8415f68c91f7f1756c0e50dc98866bb9004c0db402be7f1d8e8acd5d5365bffae1259d3d347f233bebc348e9a52ac4aebaa165eac0269015fc622
验证结果:=====true=====
私钥加密:41b200f969b3d25be82d13141c4a0f1c1058f8fd122ed3a19e2a5652a6ae8d7f790c422c29633b92166311322fd5b0e4fd06086c1b4e708b4c38513482a95d8b9f66a2f09ca48c0effd164263a2483e589acc24f30473b56cf78d60af9b66fa8701d8f071c4f197930f2c9abd4e360e356cfdd167fa35d2d6dde5bc5650d5f6f
公钥解密:123456