Java使用RSA算法

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("原文字:\t" + src);
        byte[] encodedData = RSAUtil.encryptByPublicKey(src.getBytes(), publicKey);
        System.out.println("加密后:\t" + Arrays.toString(encodedData));
        String plainText = new String(RSAUtil.decryptByPrivateKey(encodedData, privateKey));
        System.out.println("解密后: \t" + plainText);

        System.err.println("私钥签名——公钥验证签名");
        byte[] sign = RSAUtil.sign(encodedData, privateKey);
        System.err.println("签名:\t\t" + Arrays.toString(sign));
        boolean status = RSAUtil.verify(encodedData, publicKey, sign);
        System.err.println("验证结果:\t" + 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("公钥加密:\t" + cipherText);
        String plainText = RSAWrapper.decryptByPrivateKey(cipherText, privateKey);
        System.out.println("私钥解密:\t" + 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("私钥加密:\t" + cipherText);
        plainText = RSAWrapper.decryptByPublicKey(cipherText, pubKey);
        System.out.println("公钥解密:\t" + plainText);

        System.err.println("私钥签名——公钥验证签名");
        String sign = RSAWrapper.sign(cipherText, privateKey);
        System.err.println("签名:\t\t" + sign);
        boolean status = RSAWrapper.verify(cipherText, pubKey, sign);
        System.err.println("验证结果:\t" + status);
    }
}