本文 字数: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