加密和签名使用不同的密钥对,签名密钥对的私钥用于签名,其对应的公钥用于验证签名。
加密密钥对的公钥用于加密,其对应的私钥用于解密。
1.生成密钥对
/** * 生成RSA随机密钥对(公钥和私钥) * @return */ public static Map<String, String> createKeyPair() throws Exception { Map<String,String> keyPairMap = new HashMap<>(); // 密钥生成器,基于RSA算法 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); // 初始化密钥生成器,密钥大小为96-1024位 keyPairGenerator.initialize(1024, SecureRandom.getInstance("SHA1PRNG")); // 生成一个密钥对,保存在KeyPair中 KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 获取公钥及公钥字节数组 PublicKey publicKey = keyPair.getPublic(); byte[] publicKeyBytes = publicKey.getEncoded(); // 获取私钥及私钥字节数组 PrivateKey privateKey = keyPair.getPrivate(); byte[] privateKeyBytes = privateKey.getEncoded(); // 转换成16进制字符保存在map中 keyPairMap.put(PUBLIC_KEY, byte2Hex(publicKeyBytes)); keyPairMap.put(PRIVATE_KEY, byte2Hex(privateKeyBytes)); return keyPairMap; }
2.RSA公钥加密
/** * RSA公钥加密。RSA加密算法对于加密数据长度是有要求的,一般来说,明文长度大小小于等于密钥长度(bytes)-11. * 解决这个问题要对较长的明文进行分段加解密(这里不做实现) * @param contents * @param publicKeyString * @return */ public static String encryptWithPublicKey(String contents, String publicKeyString) throws Exception { // 判断入参非空 // 获取公钥 PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(hex2Byte(publicKeyString))); // RSA公钥加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptBytes = cipher.doFinal(contents.getBytes("UTF-8")); return byte2Hex(encryptBytes); }
3.RSA私钥解密
/** * RSA私钥解密。同样这里不做分段实现 * @param encryptContents * @param privateKeyString * @return */ public static String decryptWithPrivateKey(String encryptContents, String privateKeyString) throws Exception { // 判断非空 // 获取私钥 PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(hex2Byte(privateKeyString))); // RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptBytes = cipher.doFinal(hex2Byte(encryptContents)); return new String(decryptBytes, "UTF-8"); }
4.RSA私钥加密(用于签名)
/** * RSA私钥加密(用于签名) * @param contents * @param privateKeyString * @return */ public static String encryptWithPrivateKey(String contents, String privateKeyString) throws Exception { // 判断非空 // 获取私钥 PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(hex2Byte(privateKeyString))); // RSA加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] encryptBytes = cipher.doFinal(contents.getBytes("UTF-8")); return byte2Hex(encryptBytes); }
5.RSA公钥解密(用于验签)
/** * RSA公钥解密,用于验证签名 * @param encryptContents * @param publicKeyString * @return */ public static String decryptWithPublicKey(String encryptContents, String publicKeyString) throws Exception { // 判断非空 // 获取公钥 PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(hex2Byte(publicKeyString))); // RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] decryptBytes = cipher.doFinal(hex2Byte(encryptContents)); return new String(decryptBytes, "UTF-8"); }
--------------------------------------
工具方法
/** * 将byte[]数组转换成16进制字符。一个byte生成两个字符,长度对应1:2 * @param bytes,输入byte[]数组 * @return 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; }
原文地址:https://www.cnblogs.com/hello4world/p/12216112.html
时间: 2024-10-09 03:57:36