RSA算法代码如下:
package gj.secure; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * @author areful * Date: 2019/2/12 */ @SuppressWarnings("WeakerAccess") public class RSAUtil { public static final String KEY_ALGORITHM_AES = "RSA"; public static final String KEY_ALGORITHM_AES_PCKS1PADDING = "RSA/ECB/PKCS1PADDING"; public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; private static final int MAX_ENCRYPT_BLOCK = 117; private static final int MAX_DECRYPT_BLOCK = 128; public static KeyPair genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM_AES); keyPairGen.initialize(1024); return keyPairGen.generateKeyPair(); } public static byte[] encryptByPublicKey(byte[] data, byte[] pubKey) throws Exception { Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_AES_PCKS1PADDING); cipher.init(Cipher.ENCRYPT_MODE, KeyFactory.getInstance(KEY_ALGORITHM_AES).generatePublic(new X509EncodedKeySpec(pubKey))); return doFinal(cipher, data, data.length, true); } public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_AES); Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_AES_PCKS1PADDING); cipher.init(Cipher.ENCRYPT_MODE, keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey))); return doFinal(cipher, data, data.length, true); } public static byte[] decryptByPublicKey(byte[] encryptedData, byte[] publicKey) throws Exception { Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_AES_PCKS1PADDING); cipher.init(Cipher.DECRYPT_MODE, KeyFactory.getInstance(KEY_ALGORITHM_AES).generatePublic(new X509EncodedKeySpec(publicKey))); return doFinal(cipher, encryptedData, encryptedData.length, false); } public static byte[] decryptByPrivateKey(byte[] encryptedData, byte[] privateKey) throws Exception { Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_AES_PCKS1PADDING); cipher.init(Cipher.DECRYPT_MODE, KeyFactory.getInstance(KEY_ALGORITHM_AES).generatePrivate(new PKCS8EncodedKeySpec(privateKey))); return doFinal(cipher, encryptedData, encryptedData.length, false); } public static byte[] sign(byte[] data, byte[] privateKey) throws Exception { Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(KeyFactory.getInstance(KEY_ALGORITHM_AES).generatePrivate(new PKCS8EncodedKeySpec(privateKey))); signature.update(data); return signature.sign(); } public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception { Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(KeyFactory.getInstance(KEY_ALGORITHM_AES).generatePublic(new X509EncodedKeySpec(publicKey))); signature.update(data); return signature.verify(sign); } private static byte[] doFinal(Cipher cipher, byte[] data, int inputLen, boolean isEncryptMode) throws Exception { int maxBlockSize = isEncryptMode ? MAX_ENCRYPT_BLOCK : MAX_DECRYPT_BLOCK; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; while (inputLen - offSet > 0) { if (inputLen - offSet > maxBlockSize) { cache = cipher.doFinal(data, offSet, maxBlockSize); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * maxBlockSize; } byte[] result = out.toByteArray(); out.close(); return result; } }
如果在网上传输,不能直接传byte[]类型数组,部分字节会和网络传输协议控制类字符冲突。通常都是转换一次,例如使用Base64编码发送,接收方收到后再Base64解码,这样就不会有冲突了。
以下是Base64封装:
package gj.secure; import java.security.KeyFactory; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * @author areful * Date: 2019/2/12 */ public class RSAWrapper extends RSAUtil { public static String encryptByPublicKey(String data, String publicKey) throws Exception { return encode2Base64(encryptByPublicKey(decodeFromBase64(data), decodeFromBase64(publicKey))); } public static String encryptByPrivateKey(String data, String privateKey) throws Exception { return encode2Base64(encryptByPrivateKey(decodeFromBase64(data), decodeFromBase64(privateKey))); } public static String decryptByPublicKey(String data, String publicKey) throws Exception { return new String(decryptByPublicKey(decodeFromBase64(data), decodeFromBase64(publicKey))); } public static String decryptByPrivateKey(String data, String privateKey) throws Exception { return new String(decryptByPrivateKey(decodeFromBase64(data), decodeFromBase64(privateKey))); } public static String sign(String data, String privateKey) throws Exception { Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(KeyFactory.getInstance(KEY_ALGORITHM_AES) .generatePrivate(new PKCS8EncodedKeySpec(decodeFromBase64(privateKey)))); signature.update(decodeFromBase64(data)); return encode2Base64(signature.sign()); } public static boolean verify(String data, String publicKey, String sign) throws Exception { Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(KeyFactory.getInstance(KEY_ALGORITHM_AES) .generatePublic(new X509EncodedKeySpec(decodeFromBase64(publicKey)))); signature.update(decodeFromBase64(data)); return signature.verify(decodeFromBase64(sign)); } private static String encode2Base64(byte[] data) { return java.util.Base64.getEncoder().encodeToString(data); } private static byte[] decodeFromBase64(String src) { return java.util.Base64.getDecoder().decode(src); } }
测试代码:
package gj.secure; import org.junit.Test; import java.security.KeyPair; import java.util.Arrays; /** * @author areful * Date: 2019/2/12 */ public class TestRSAUtil { @Test public void testEncryptByPublicKey() throws Exception { KeyPair keyPair = RSAUtil.genKeyPair(); byte[] publicKey = keyPair.getPublic().getEncoded(); byte[] privateKey = keyPair.getPrivate().getEncoded(); System.err.println("私钥加密——公钥解密"); String src = "第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。"; System.out.println("原文字: " + src); byte[] encodedData = RSAUtil.encryptByPublicKey(src.getBytes(), publicKey); System.out.println("加密后: " + Arrays.toString(encodedData)); String plainText = new String(RSAUtil.decryptByPrivateKey(encodedData, privateKey)); System.out.println("解密后: " + plainText); System.err.println("私钥签名——公钥验证签名"); byte[] sign = RSAUtil.sign(encodedData, privateKey); System.err.println("签名: " + Arrays.toString(sign)); boolean status = RSAUtil.verify(encodedData, publicKey, sign); System.err.println("验证结果: " + status); } }
package gj.secure; import org.junit.Test; import java.util.Base64; /** * @author areful * Date: 2019/2/12 */ public class TestRSAWrapper { @Test public void testEncryptByPrivateKey() throws Exception { String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW7SUABMZltXXlQ0ZG2WZe6i64Jq0hb6QpC0cvA49zUyrzkfQrH2" + "JYoPohmVWqKn+vYj4HKFtBHsPUI/3COLv/tQ7oOQGrf9o0JhaZwktiq+pJbTe2jlw8UZm8+xhIDGGDZ/dXQyRHKfkTyJJqwVv1" + "dE1CIFenCoPp2JztsYS7iQIDAQAB"; String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANbtJQAExmW1deVDRkbZZl7qLrgmrSFvpCkLRy8Dj3" + "NTKvOR9CsfYlig+iGZVaoqf69iPgcoW0Eew9Qj/cI4u/+1Dug5Aat/2jQmFpnCS2Kr6kltN7aOXDxRmbz7GEgMYYNn91dDJEcp" + "+RPIkmrBW/V0TUIgV6cKg+nYnO2xhLuJAgMBAAECgYByhAKN4v1u3ePGVzUPtPAlrHNeLUVcJmb6c4bnFueNFAgzpVXK0DsPbB" + "46Xr/VHjXQVfEk0SzmIqVG2DJyFNadq0RqGmPDTPit1cO7aWQb3fZEUUpORZt1TCqIShirzoO830w1dJJW7MhyoKUAPLLsi5be" + "rFj7VaagOnmnZTgXsQJBAPSt1Qg++6Pat/7rwB46GhlTQvY6HOa0O9IcFWf262ihTJHJApYpvEvuLA6TKRAdP7EJ2ItwkoFFjQ" + "bbKDq6I5UCQQDg3uYGKNmoIwkfVVzgcaLg4wEaAPftmS+pp3Q8l66BonBsYhG4kiYr9NepwPa9ZiSdZtXKEkkeWM6qZ1OeMXsl" + "AkEAqBsiqWa0d3BXSBLrTRk4QzwcXpWws6UTEJlw75wLQzjHJcaIO2lzUGvT4zOiW8rsrpMIL01pqt2BNjuumSK4PQJAB9K5Xe1" + "95QOTBawKlyRc7kX3e9gcx/9UUSqqOJFuWMQ19Q9UXn93JIBYIGe+Lcin7XHubiFEufGM/xCpMA+4oQJBAJRp1TLVinccyGw3v3" + "vB96WQH89SUnmk5tR5ydSrB+3qr2lsiJtcH0i5R5EjYdFpIgpUEBEmL+s/LLLP9Rd7I+k="; String text = "第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1," + "ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。"; String base64Text = Base64.getEncoder().encodeToString(text.getBytes()); //公钥加密私钥解密 String cipherText = RSAWrapper.encryptByPublicKey(base64Text, pubKey); System.out.println("公钥加密: " + cipherText); String plainText = RSAWrapper.decryptByPrivateKey(cipherText, privateKey); System.out.println("私钥解密: " + plainText); text = "第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1," + "并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功," + "Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。"; base64Text = Base64.getEncoder().encodeToString(text.getBytes()); //私钥加密公钥解密 cipherText = RSAWrapper.encryptByPrivateKey(base64Text, privateKey); System.out.println("私钥加密: " + cipherText); plainText = RSAWrapper.decryptByPublicKey(cipherText, pubKey); System.out.println("公钥解密: " + plainText); System.err.println("私钥签名——公钥验证签名"); String sign = RSAWrapper.sign(cipherText, privateKey); System.err.println("签名: " + sign); boolean status = RSAWrapper.verify(cipherText, pubKey, sign); System.err.println("验证结果: " + status); } }