[JavaSecurity] - RSA Encryption

1. RSA Algorithm

  • RSA is one of the first practical public-key cryptosystems and is widely used for secure data transmission. In such a cryptosystem, the encryption key (public key) is public and differs from the decryption key (private key) which is kept secret.
  • RSA stands for Ron Rivest, Adi Shamir and Leonard Adleman, who first publicly described it in 1978.

2. Classic usage

Tom holds private key and share his public key with Jerry (public key and private key are a pair)

  • Tom holds public key and private key. Private key, he have to keep secretly. Public key, Tom can pass to anyone he wants to communicate with, like his friend Jerry.
  • Tom put his public-private key pair into a java keystore (.jks). Because he likes java and it's very easy to operate keystore with java.

Jerry sent encrypted message to Tom

  • Jerry wrote a message (original message).
  • Jerry generated a key (secret key of AES).
  • Jerry used AES algorithm with the key he just generated to encrypt his message. 
  • Jerry used RSA algorithm with public key Tom shares with him to encrypt his key.
  • Jerry sent encrypted message and key to Tom.

Tom decrypt Jerry's message

  • Tom used RSA algorithm with his private key to decrypt Jerry's encrypted key.
  • Tom got original Jerry's encryption key
  • Tom use AES algorithm with Jerry's key to decrypt Jerry's encrypted message.
  • Tom read Jerry's original message.

3. Sample code

Save public key into a file or any other media

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;

/**
 *
 * @author wangbo
 */
public class ReadKeyStore {

    public static void main(String[] args) throws KeyStoreException, FileNotFoundException, IOException,
            NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, UnrecoverableEntryException,
            javax.security.cert.CertificateException {

        // load keystore
        FileInputStream keystoreIn = new FileInputStream(Util.PATH_KEYSTORE);
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(keystoreIn, Util.KEYSTORE_STOREPASS.toCharArray());
        keystoreIn.close();

        // get entry from keystore
        KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(
                Util.KEYSTORE_KEYPASS.toCharArray());
        KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) keystore.getEntry(
                Util.KEYSTORE_ALIAS_RSAKEY, protectionParameter);

        // get certificate
        Certificate cert = keyEntry.getCertificate();

        // get public key (we'll not use public key this time.)
        PublicKey pubKey = cert.getPublicKey();

        // get private key (we'll not use private key this time.)
        PrivateKey priKey = keyEntry.getPrivateKey();

        // store certificate into a file
        FileOutputStream certOut = new FileOutputStream(Util.PATH_CERTIFICATE);
        certOut.write(cert.getEncoded());
        certOut.close();
    }

}

Encryption

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;

/**
 *
 * @author wangbo
 */
public class RSAEncrypt {

    public static void main(String[] args) throws IOException, ClassNotFoundException,
            NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException, NoSuchProviderException, CertificateException {

        // get certificate
        FileInputStream certIn = new FileInputStream(Util.PATH_CERTIFICATE);
        byte[] certBytes = new byte[certIn.available()];
        certIn.read(certBytes);
        certIn.close();
        X509Certificate cert = X509Certificate.getInstance(certBytes);

        // get public key from certificate
        PublicKey pubKey = cert.getPublicKey();

        // generate a secret key and wrap it with public key
        KeyGenerator genKey = KeyGenerator.getInstance("AES");
        genKey.init(new SecureRandom());
        SecretKey secretKey = genKey.generateKey();

        Cipher rsaCipher = Cipher.getInstance("RSA");
        rsaCipher.init(Cipher.WRAP_MODE, pubKey);
        byte[] wrappedSecretKeyBytes = rsaCipher.wrap(secretKey);

        // write secret key into a file
        FileOutputStream secretKeyOut = new FileOutputStream(Util.PATH_SECRETKEY);
        secretKeyOut.write(wrappedSecretKeyBytes);
        secretKeyOut.close();

        // encrypt data with secret key
        Cipher aesCipher = Cipher.getInstance("AES");
        aesCipher.init(Cipher.ENCRYPT_MODE, secretKey);

        BufferedInputStream dataIn = new BufferedInputStream(new FileInputStream(Util.PATH_DATA));
        BufferedOutputStream encryptedDataOut = new BufferedOutputStream(new FileOutputStream(
                Util.PATH_DATA_ENCRYPTED));

        byte[] inBytes = new byte[aesCipher.getBlockSize()];
        byte[] outBytes;
        int len;
        while ((len = dataIn.read(inBytes)) >= 0) {
            outBytes = aesCipher.update(inBytes, 0, len);
            encryptedDataOut.write(outBytes);
        }
        outBytes = aesCipher.doFinal();
        encryptedDataOut.write(outBytes);

        dataIn.close();
        encryptedDataOut.close();
    }

}


Decryption

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 * @author WANG BO
 */
public class RSADecrypt {

    public static void main (String[] args) throws KeyStoreException, NoSuchAlgorithmException,
            CertificateException, IOException, NoSuchPaddingException, InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException, UnrecoverableEntryException {

        // get private key
        BufferedInputStream keystoreIn = new BufferedInputStream (new FileInputStream (
                Util.PATH_KEYSTORE));
        KeyStore keystore = KeyStore.getInstance (KeyStore.getDefaultType ());
        keystore.load (keystoreIn, Util.KEYSTORE_STOREPASS.toCharArray ());
        keystoreIn.close ();

        KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)keystore.getEntry (
                Util.KEYSTORE_ALIAS_RSAKEY,
                new KeyStore.PasswordProtection (Util.KEYSTORE_KEYPASS.toCharArray ()));
        PrivateKey priKey = keyEntry.getPrivateKey ();

        // get encrypted key and unwrap it with private key
        Cipher rsaCipher = Cipher.getInstance ("RSA");
        rsaCipher.init (Cipher.UNWRAP_MODE, priKey);

        FileInputStream unwrappedSecretKeyIn = new FileInputStream (Util.PATH_SECRETKEY);
        byte[] unwrappedSecretKeyBytes = new byte[unwrappedSecretKeyIn.available ()];
        unwrappedSecretKeyIn.read (unwrappedSecretKeyBytes);
        unwrappedSecretKeyIn.close ();
        Key secretkey = rsaCipher.unwrap (unwrappedSecretKeyBytes, "AES", Cipher.SECRET_KEY);

        // get encrypted data and decrypt it with secret key
        BufferedInputStream encryptedDataIn = new BufferedInputStream (new FileInputStream (
                Util.PATH_DATA_ENCRYPTED));
        BufferedOutputStream decryptedDataOut = new BufferedOutputStream (new FileOutputStream (
                Util.PATH_DATA_DECRYPTED));

        Cipher aes = Cipher.getInstance ("AES");
        aes.init (Cipher.DECRYPT_MODE, secretkey);

        byte[] inBytes = new byte[aes.getBlockSize ()];
        byte[] outBytes;
        int len;
        while ((len = encryptedDataIn.read (inBytes)) >= 0) {
            outBytes = aes.update (inBytes, 0, len);
            decryptedDataOut.write (outBytes);
        }
        outBytes = aes.doFinal ();
        decryptedDataOut.write (outBytes);

        encryptedDataIn.close ();
        decryptedDataOut.close ();

    }
}

Why don't encrypt the message directly with RSA algorithm?

  • RSA can encrypt data of limited size, the length is not possible to be over the length of RSA key. With the commonly used "v1.5 padding" and a 2048-bit RSA key, the maximum size of data which can be encrypted with RSA is 245 bytes. No more.
  • Encrypt big chunk data is very expensive
  • There is not any problem if the data you want to encrypt is very short.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值