RSA非对称加密算法

非对称加密

  1. 具体算法看这位大神详解 https://blog.csdn.net/jijianshuai/article/details/80582187
  2. 常用用途

api接口数据传输等

  1. 加密解密用法

公钥暴露在网络上,私钥在本地保存,凡是能拿到公钥的人都可以加密信息,但是使用公钥加密的数据,无法再次使用公钥解开,所以一般采用公钥加密私钥解密的方式

  1. 签名/验签的用法

一般采用私钥进行签名,然后把签名和明文数据一起传送给拥有公钥的一方,拥有公钥的一方,可以使用公钥验证此签名是否为对应私钥签名,以防止数据篡改

代码


import javax.crypto.Cipher;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 

* Utils for RSA Encrypt *

    *
  • Use private key to decrypt {@link #decrypt(Key, byte[])} data;
  • *
  • Use public key to encrypt {@link #encrypt(Key, byte[])} data;
  • *
  • Use sign {@link #sign(byte[], PrivateKey)} to generate a signature;
  • *
  • Use the verify {@link #verify(byte[], PublicKey, String)} to valuation if has be hijacked;
  • *
*

* * @author Wilton Jia * @date 2020-09-29 * @since 1.0 */ public class RSAEncrypt { /** * array of byte data, for transform strings */ private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * Algorithm of Encrypt */ private final static String KEY_RSA = "RSA"; /** * Algorithm of Signature */ private final static String KEY_RSA_SIGNATURE = "MD5withRSA"; /** * Public key name */ private final static String publicKeyName = "publicKey"; /** * Private key name */ private final static String privateKeyName = "privateKey"; /** * Generate a pair of random keys * @param filePath location of key files */ public static Map genKeyPair(String filePath) throws Exception { // get KeyGenerator KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); // Init the KeyGenerator, size of key :96-1024 bit keyPairGen.initialize(2048); // key pair KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // key string Base64.Encoder base64Encoder = Base64.getEncoder(); String publicKeyString = base64Encoder.encodeToString(publicKey.getEncoded()); String privateKeyString = base64Encoder.encodeToString(privateKey.getEncoded()); String uuid = UUIDGenerator.generateWithout_(); // Result for file path Map pairs = new HashMap<>(2); String publicKeyFilePath = filePath + File.separator + uuid+ "_publicKey.pem"; String privateKeyFilePath = filePath + File.separator + uuid+ "_privateKey.pem"; pairs.put(publicKeyName,publicKeyFilePath); pairs.put(privateKeyName,privateKeyFilePath); // Write files to local FileWriter publicKeyWriter = new FileWriter(publicKeyFilePath); FileWriter privateKeyWriter = new FileWriter(privateKeyFilePath); BufferedWriter publicKeyBufferWriter = new BufferedWriter(publicKeyWriter); BufferedWriter privateKeyBufferWriter = new BufferedWriter(privateKeyWriter); //Close streams publicKeyBufferWriter.write(publicKeyString); privateKeyBufferWriter.write(privateKeyString); publicKeyBufferWriter.flush(); publicKeyBufferWriter.close(); publicKeyWriter.close(); privateKeyBufferWriter.flush(); privateKeyBufferWriter.close(); privateKeyWriter.close(); return pairs; } /** * Load a key from local file, first step is get the file byte array, * then transform the byte array to a RSAKey, * @param path the pem file path or * @param type Implements of RSAKey, RSAPublicKey or RSAPrivateKey * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @return {@code RSAPublicKey, RSAPrivateKey} */ public static RSAKey loadKeyFromFile(String path, Class type) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { //load the key string from file File file = new File(path); FileInputStream fileInputStream = new FileInputStream(path); DataInputStream dis = new DataInputStream(fileInputStream); byte[] keyBytes = new byte[(int)file.length()]; dis.readFully(keyBytes); dis.close(); fileInputStream.close(); // parse the key string to a key KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA); EncodedKeySpec keySpec = null; // while need a public key keyBytes = Base64.getDecoder().decode(keyBytes); if(type.getName().equals(RSAPublicKey.class.getName())){ keySpec = new X509EncodedKeySpec(keyBytes); return (RSAPublicKey)keyFactory.generatePublic(keySpec); }else if(type.getName().equals(RSAPrivateKey.class.getName())){ keySpec = new PKCS8EncodedKeySpec(keyBytes); return (RSAPrivateKey)keyFactory.generatePrivate(keySpec); } return null; } /** * Use the key to encrypt some data * @param key publicKey or privateKey * @param plainTextData clear data array * @return encrypted data bytes * @throws Exception */ public static byte[] encrypt(Key key, byte[] plainTextData) throws Exception { if (key == null) { throw new Exception("key could not be null"); } Cipher cipher = Cipher.getInstance(KEY_RSA); cipher.init(Cipher.ENCRYPT_MODE, key); return cipher.doFinal(plainTextData); } /** * Use key to decrypt data * @param key public key or private key * @param cipherData encrypt data * @return clear data array * @throws Exception */ public static byte[] decrypt(Key key, byte[] cipherData) throws Exception { if (key == null) { throw new Exception("private key could not be empty or null"); } Cipher cipher = Cipher.getInstance(KEY_RSA);; cipher.init(Cipher.DECRYPT_MODE, key); return cipher.doFinal(cipherData); } /** * Use Private key to sign *

* could be a public key, but not suggest, cause you should write your sign by your self * and this method provide EncodedKeySpec was a PKCS8EncodedKeySpec, if you want to use a public key to sign, * you should change {@code PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes)} * to {@code X509EncodedKeySpec pkcs = new X509EncodedKeySpec(bytes)} *

* @param data clear data * @param privateKey a key encoded by Base64 * @throws Exception */ public static String sign(byte[] data, PrivateKey privateKey) throws Exception { // create the real Signature Object Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); signature.initSign(privateKey); signature.update(data); return encryptBase64(signature.sign()); } /** * Verify the Sign context * * @param data encrypted data * @param publicKey a base64 key * @param sign * @return if success return {@code true} else return {@code false} */ public static boolean verify(byte[] data, PublicKey publicKey, String sign) { boolean flag = false; try { // to verify Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); signature.initVerify(publicKey); signature.update(data); flag = signature.verify(decryptBase64(sign)); } catch (Exception e) { e.printStackTrace(); } return flag; } /** * Parse a byte array to a hex String * @param data input byte array * @return hex String */ public static String byteArrayToString(byte[] data) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < data.length; i++) { // get high four bit as a index ,then parse to hex, be careful to forget no sign left move stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]); // get the lower four bit as a index ,get hex sign stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]); if (i < data.length - 1) { stringBuilder.append(' '); } } return stringBuilder.toString(); } /** * BASE64 decode * @param key base64 string needs to decode * @return clear data array */ public static byte[] decryptBase64(String key) throws Exception { return Base64.getDecoder().decode(key); } /** * BASE64 encode * @param key data array need to encode * @return a string */ public static String encryptBase64(byte[] key) throws Exception { return Base64.getEncoder().encodeToString(key); } }

测试

  1. 生成密钥
@Test
public void test1() throws Exception {
    Map keyPair = RSAEncrypt.genKeyPair(path);
    for (String s : keyPair.keySet()) {
        System.out.printf("%s: %s", s, keyPair.get(s));
        //4bfda50f21e540f19ab394218e62ccb7_privateKey.pem
        //4bfda50f21e540f19ab394218e62ccb7_publicKey.pem
    }
}
  1. 公钥加密/私钥解密
@Test
public void test2() throws Exception {
    String publicKey = "4bfda50f21e540f19ab394218e62ccb7_publicKey.pem";
    RSAPublicKey rsaPublicKey = (RSAPublicKey)RSAEncrypt.loadKeyFromFile(path + publicKey, RSAPublicKey.class);
    byte[] encrypt = RSAEncrypt.encrypt(rsaPublicKey, "123456ABc".getBytes());
    System.out.println(new String(Base64Utils.encode(encrypt)));
    String privateKey = "4bfda50f21e540f19ab394218e62ccb7_privateKey.pem";
    RSAPrivateKey key = (RSAPrivateKey)RSAEncrypt.loadKeyFromFile(path + privateKey, RSAPrivateKey.class);
    byte[] decrypt = RSAEncrypt.decrypt(key, encrypt);
    System.out.println(new String(decrypt));
}
  1. 私钥签名/公钥验签
@Test
public void test4() throws Exception {
    String privateKey = "4bfda50f21e540f19ab394218e62ccb7_privateKey.pem";
    RSAPrivateKey key = (RSAPrivateKey)RSAEncrypt.loadKeyFromFile(path + privateKey, RSAPrivateKey.class);
    String sign = RSAEncrypt.sign("123456AbCd".getBytes(), key);
    System.out.println(sign);
    String publicKey = "4bfda50f21e540f19ab394218e62ccb7_publicKey.pem";
    RSAPublicKey rsaPublicKey = (RSAPublicKey)RSAEncrypt.loadKeyFromFile(path + publicKey, RSAPublicKey.class);
    boolean verify = RSAEncrypt.verify("123456AbCd1".getBytes(), rsaPublicKey, sign);
    System.out.println(verify);
}

本人自己整理的工具类集合

geeking-common-utils
欢迎各位大神将自己的工具类贡献,省去每次找一个工具类的烦恼

你可能感兴趣的:(RSA非对称加密算法)