在Java中的使用RSA

几个月前心血来潮想用Java写一个类似于QQ的软件,数据保护部分想用RSA+AES,就到网上搜索了一下相关资料。Java的加密库做得挺好,对于RSA和AES都支持得挺好。

根据自己需要封装了一个RSAHelper和测试类。

RSAHelper:

package freetalklibrary;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author Neil
 *
 * To provide a wrapper class for RSA operations,including key
 * generation,encryption,decryption,signing and signature verification. RSA can
 * be used in the several ways: Encrypt the content using .
 */
public class RSAHelper {

    /**
     * Key algorithm to be used in this class.
     */
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * Default key length. The value shall be in the range of 512-65536.
     */
    private static final int KEY_LENGTH = 1024;

    /**
     * Identifier of pubic key in the Map.
     */
    public static final String PUBLIC_KEY = "PublicKey";

    /**
     * Identifier of private key in the Map.
     */
    public static final String PRIVATE_KEY = "PrivateKey";

    /**
     * Algorithm to be used for signature and verification.
     */
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /**
     * Generate a RSA key pair with public key and private key.
     *
     * @param keyMap to save the key pair, the public key is indicated by
     * "PublicKey" and private key is indicated by "PrivateKey".
     * @return
     */
    public static Result generateKeyPair(Map<String, Object> keyMap) {
        Result result = new Result();
        //Get one instance of KeyPairGenerator with RSA.
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
            result.setFailure();
        }

        if (result.isSuccess()) {
            //Get a random seed.
            SecureRandom secureRandom = new SecureRandom();

            //Use current datetime as random seed.
            String currentDateTime = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
            secureRandom.setSeed(currentDateTime.getBytes());

            //Initialze the key generator with the random number provider. We need to call initialze everytime to get a NEW key pair.
            keyPairGenerator.initialize(KEY_LENGTH, secureRandom);

            //Ready to generate a key pair.
            KeyPair keyPair = keyPairGenerator.genKeyPair();

            //Get public and private key.
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            keyMap.put(PUBLIC_KEY, publicKey.getEncoded());
            keyMap.put(PRIVATE_KEY, privateKey.getEncoded());
        }

        return result;
    }

    /**
     * Save the keys into the key file.
     *
     * @param keyPair key pair to be saved into the file.
     * @param publicKeyFileName file to save public key.
     * @param privateKeyFileName file to save private key.
     */
    public static void saveKeyPair(Map<String, Object> keyPair, String publicKeyFileName, String privateKeyFileName) {
        //Write public key into the key file.
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(publicKeyFileName);
            byte[] publicKey = (byte[]) keyPair.get(PUBLIC_KEY);
            fileOutputStream.write(publicKey);
            fileOutputStream.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        //Write private key into the key file.
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(privateKeyFileName);
            byte[] privateKey = (byte[]) keyPair.get(PRIVATE_KEY);
            fileOutputStream.write(privateKey);
            fileOutputStream.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Get the key from local file.
     *
     * @param keyFileName file containing the key.
     *
     * @return byte array containing the key.
     */
    public static byte[] getKey(String keyFileName) {
        byte[] keyBytes = null;
        //Get key from file.
        try {
            File file = new File(keyFileName);
            FileInputStream fileInputStream = new FileInputStream(file);
            DataInputStream dataInputStream = new DataInputStream(fileInputStream);

            //Allocate the buffer.
            keyBytes = new byte[(int) file.length()];

            //Read them all.
            dataInputStream.readFully(keyBytes);

            dataInputStream.close();
            fileInputStream.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return keyBytes;
    }

    /**
     * Encrypt the data with the public key.
     *
     * @param data data to be encrypted.
     * @param offset offset of data to be encrypted.
     * @param length length of data to be encrypted.
     * @param publicKeyBytes public key in binary format.
     * @return encrypted data.
     */
    public static byte[] encryptWithPublicKey(byte[] data, int offset, int length, byte[] publicKeyBytes) {

        byte[] encryptedData = null;

        try {
            //Create a new X509EncodedKeySpec with the given encoded key.
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);

            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            //Get the public key from the provided key specification.
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            //Init the ciper.
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

            //Encrypt mode!
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            //Do the encryption now !!!!
            encryptedData = cipher.doFinal(data, offset, length);

        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return encryptedData;
    }

    /**
     * Encrypt the data with private key.
     *
     * @param data data to be encrypted.
     * @param offset offset of data to be encrypted.
     * @param length length of data to be encrypted.
     * @param privateKeyBytes private key in binary format.
     * @return encrypted data.
     */
    public static byte[] encryptWithPrivateKey(byte[] data, int offset, int length, byte[] privateKeyBytes) {
        byte[] encryptedData = null;

        try {
            // Create a new PKCS8EncodedKeySpec with the given encoded key.
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            //Get the private key from the provided key specification.
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

            //Init the ciper.
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

            //Encrypt mode!
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);

            //Do the encryption now !!!!
            encryptedData = cipher.doFinal(data, offset, length);

        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return encryptedData;
    }

    /**
     * Decrypt data with public key.
     *
     * @param data data to be decrypted.
     * @param offset offset of data to be decrypted.
     * @param length length of data to be decrypted.
     * @param publicKeyBytes public key in binary format.
     * @return decrypted data.
     */
    public static byte[] decryptWithPublicKey(byte[] data, int offset, int length, byte[] publicKeyBytes) {

        byte[] encryptedData = null;

        try {
            //Create a new X509EncodedKeySpec with the given encoded key.
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);

            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            //Get the public key from the provided key specification.
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            //Init the ciper.
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

            //Decrypt mode!
            cipher.init(Cipher.DECRYPT_MODE, publicKey);

            //Do the decryption now !!!!
            encryptedData = cipher.doFinal(data, offset, length);

        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return encryptedData;
    }

    /**
     * Decrypt the data with private key bytes.
     *
     * @param data data to be decrypted.
     * @param offset offset of data to be decrypted.
     * @param length length of data to be decrypted.
     * @param privateKeyBytes private key in binary format.
     * @return decrypted data.
     */
    public static byte[] decryptWithPrivateKey(byte[] data, int offset, int length, byte[] privateKeyBytes) {
        byte[] encryptedData = null;

        try {
            // Create a new PKCS8EncodedKeySpec with the given encoded key.
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            //Get the private key from the provided key specification.
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

            //Init the ciper.
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

            //Decrypt mode!
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            //Do the decryption now !!!!
            encryptedData = cipher.doFinal(data, offset, length);

        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return encryptedData;
    }

    /**
     * Decrypt the data with private key.
     *
     * @param data data to be decrypted.
     * @param offset offset of data to be decrypted.
     * @param length length of data to be decrypted.
     * @param privateKey private key.
     * @return decrypted data.
     */
    public static byte[] decryptWithPrivateKey(byte[] data, int offset, int length, PrivateKey privateKey) {
        byte[] encryptedData = null;

        try {
            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);


            //Init the ciper.
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

            //Decrypt mode!
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            //Do the decryption now !!!!
            encryptedData = cipher.doFinal(data, offset, length);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return encryptedData;
    }
    
    /**
     * Sign the data with the private key.
     *
     * @param data data to be signed.
     * @param offset offset of data to be signed.
     * @param length length of data to be signed.
     * @param privateKeyBytes private key in binary format.
     * @return signed data.
     */
    public static byte[] sign(byte[] data, int offset, int length, byte[] privateKeyBytes) {
        byte[] signedData = null;
        try {
            // Create a new PKCS8EncodedKeySpec with the given encoded key.
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            //Get the private key from the provided key specification.
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

            //Create the Signature instance with RSA MD5.
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

            //Use private key to do the signature.
            signature.initSign(privateKey);

            //Updates the data to be signed or verified, using the specified array of bytes.
            signature.update(data, offset, length);

            //Sign it now.
            signedData = signature.sign();
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | SignatureException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return signedData;
    }

    /**
     * Verify the signature.
     *
     * @param data data signed.
     * @param offset offset of data to be verified.
     * @param length length of data to be verified.
     * @param publicKeyBytes public key in binary format.
     * @param dataSignature signature for the data.
     * @return Whether the signature is fine.
     */
    public static boolean verify(byte[] data, int offset, int length, byte[] publicKeyBytes, byte[] dataSignature) {
        boolean result = false;
        try {
            //Create a new X509EncodedKeySpec with the given encoded key.
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);

            //RSA key factory.
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

            //Get the public key from the provided key specification.
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            //Create the Signature instance with RSA MD5.
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

            //Use pubic key to verify the signature.
            signature.initVerify(publicKey);

            //Updates the data to be signed or verified, using the specified array of bytes.
            signature.update(data, offset, length);

            //Verifies the passed-in signature.
            result = signature.verify(dataSignature);

        } catch (NoSuchAlgorithmException | InvalidKeySpecException | SignatureException | InvalidKeyException ex) {
            Logger.getLogger(RSAHelper.class.getName()).log(Level.SEVERE, null, ex);
        }

        return result;
    }
}

测试类:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import freetalklibrary.RSAHelper;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Administrator
 */
public class RSAHelperTest {

    public static void main(String[] args) {
        testDecryption1();
        testDecryption2();
        testSignature();
    }

    private static void testDecryption1() {
        try {
            //Create RSA key pair.
            Map<String, Object> keyPair = new HashMap();
            RSAHelper.generateKeyPair(keyPair);

            //Get public key and private key from the result.
            byte[] pubicKeyBytes = (byte[]) keyPair.get(RSAHelper.PUBLIC_KEY);
            byte[] privateKeyBytes = (byte[]) keyPair.get(RSAHelper.PRIVATE_KEY);

            //Encrypt the test data with public key then decrypt it with private key.
            String inputString = "Hi, this is neil's test data. Don't try to play tricks with me.";
            byte[] dataEncryptedWithPublicKey = RSAHelper.encryptWithPublicKey(inputString.getBytes(), 0, inputString.getBytes().length, pubicKeyBytes);
            byte[] dataDecryptedWithPrivateKey = RSAHelper.decryptWithPrivateKey(dataEncryptedWithPublicKey, 0, dataEncryptedWithPublicKey.length, privateKeyBytes);
            String outputString = new String(dataDecryptedWithPrivateKey);
            System.out.println(outputString);

        } catch (Exception ex) {
            Logger.getLogger(RSAHelperTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private static void testDecryption2() {
        try {
            //Create RSA key pair.
            Map<String, Object> keyPair = new HashMap();
            RSAHelper.generateKeyPair(keyPair);

            //Get public key and private key from the result.
            byte[] publicKeyBytes = (byte[]) keyPair.get(RSAHelper.PUBLIC_KEY);
            byte[] privateKeyBytes = (byte[]) keyPair.get(RSAHelper.PRIVATE_KEY);

            //Encrypt the test data with private key then decrypt it with public key.
            String inputString = "Hi, this is neil's test data. Don't try to play tricks with me.";
            byte[] dataEncryptedWithPrivateKey = RSAHelper.encryptWithPrivateKey(inputString.getBytes(), 0, inputString.getBytes().length, privateKeyBytes);
            byte[] dataDecryptedWithPublicKey = RSAHelper.decryptWithPublicKey(dataEncryptedWithPrivateKey, 0, dataEncryptedWithPrivateKey.length, publicKeyBytes);
            String outputString = new String(dataDecryptedWithPublicKey);
            System.out.println(outputString);

        } catch (Exception ex) {
            Logger.getLogger(RSAHelperTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void testSignature() {
        try {
            //Create RSA key pair.
            Map<String, Object> keyPair = new HashMap();
            RSAHelper.generateKeyPair(keyPair);

            //Get public key and private key from the resut.
            byte[] publicKeyBytes = (byte[]) keyPair.get(RSAHelper.PUBLIC_KEY);
            byte[] privateKeyBytes = (byte[]) keyPair.get(RSAHelper.PRIVATE_KEY);

            //Generate the signature then verify the result.
            String inputString = "Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.Hi, this is neil's test data. Don't try to play tricks with me.";
            byte[] dataSignature = RSAHelper.sign(inputString.getBytes(), 0, inputString.getBytes().length, privateKeyBytes);
            boolean result = RSAHelper.verify(inputString.getBytes(), 0, inputString.getBytes().length, publicKeyBytes, dataSignature);

            System.out.println(result);

        } catch (Exception ex) {
            Logger.getLogger(RSAHelperTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值