English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Java Encryption and Decryption Technology Series - Detailed Explanation of RSA

It feels like a long time since I last wrote a blog post. Let me vent first. This month, the company has been working overtime, with releases, going live, and new projects being too tight, so I won't go into details. Today, let's talk about how important asymmetric encryption really is. Asymptotic encryption is indispensable in our daily lives.

Concept

Before discussing RSA, let's first talk about what asymmetric encryption is. When discussing symmetric encryption, it was mentioned that symmetric encryption algorithms use the same key for encryption and decryption, and both parties must use the same key to communicate normally. However, asymmetric encryption is not the case. Asymmetric encryption algorithms require two keys for encryption and decryption, namely the public key and the private key.

One point to note is that this public key and private key must be a pair. If data is encrypted with the public key, only the corresponding private key can decrypt it, and vice versa. Since encryption and decryption use two different keys, this algorithm is called asymmetric encryption algorithm.

Working process

As shown in the figure below, data is transmitted between A and B using asymmetric encryption.

The main algorithms used in asymmetric encryption are: RSA, Elgamal, knapsack algorithm, Rabin, D-H, ECC (Elliptic Curve Cryptography) and others. Today, we mainly introduce RSA, and for other algorithms, we will choose several to introduce in the future.

RSA

In fact, as early as 1978 years ago, RSA had already appeared, and it was the first algorithm that could be used for both data encryption and digital signature. It is easy to understand and operate, and it is also very popular. Its principle is as described in the above working process.

The RSA algorithm is based on a very simple number theory fact: it is very easy to multiply two large prime numbers, but it is extremely difficult to factorize their product, so the product can be publicly disclosed as the encryption key.

Code implementation

Let's take a look at the specific code implementation.

import com.google.common.collect.Maps; 
import sun.misc.BASE64Decoder; 
import sun.misc.BASE64Encoder; 
import javax.crypto.Cipher; 
import java.security.*; 
import java.security.interfaces.RSAPrivateKey; 
import java.security.interfaces.RSAPublicKey; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.spec.X509EncodedKeySpec; 
import java.util.Map; 
/** 
 * Created by xiang.li on 2015/3/3. 
 * RSA encryption and decryption utility class 
 */ 
public class RSA { 
  /** 
   * Define the encryption method 
   */ 
  private final static String KEY_RSA = "RSA"; 
  /** 
   * Define the signature algorithm 
   */ 
  private final static String KEY_RSA_SIGNATURE = "MD"5withRSA"; 
  /** 
   * Define the public key algorithm 
   */ 
  private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey"; 
  /** 
   * Define the private key algorithm 
   */ 
  private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey"; 
  /** 
   * Initialize the key 
   * @return 
   */ 
  public static Map<String, Object> init() { 
    Map<String, Object> map = null; 
    try { 
      KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA); 
      generator.initialize(1024); 
      KeyPair keyPair = generator.generateKeyPair(); 
      // Public key 
      RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 
      // Private key 
      RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 
      // Wrap the key into a map 
      map = Maps.newHashMap(); 
      map.put(KEY_RSA_PUBLICKEY, publicKey); 
      map.put(KEY_RSA_PRIVATEKEY, privateKey); 
    } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
    } 
    return map; 
  } 
  /** 
   * Use the private key to generate a digital signature for the information 
   * @param data Encrypted data 
   * @param privateKey Private key 
   * @return 
   */ 
  public static String sign(byte[] data, String privateKey) { 
    String str = ""; 
    try { 
      // Decrypt by base64Encoded private key 
      byte[] bytes = decryptBase64(privateKey); 
      // Construct PKCS8EncodedKeySpec object 
      PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes); 
      // Specified encryption algorithm 
      KeyFactory factory = KeyFactory.getInstance(KEY_RSA); 
      // Obtain the private key object 
      PrivateKey key = factory.generatePrivate(pkcs); 
      // Use the private key to generate a digital signature for the information 
      Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); 
      signature.initSign(key); 
      signature.update(data); 
      str = encryptBase64(signature.sign()); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return str; 
  } 
  /** 
   * Verify digital signature 
   * @param data Encrypted data 
   * @param publicKey Public key 
   * @param sign Digital signature 
   * @return Return true if verification is successful, false otherwise 
   */ 
  public static boolean verify(byte[] data, String publicKey, String sign) { 
    boolean flag = false; 
    try { 
      // Decrypt by base64Encoded public key 
      byte[] bytes = decryptBase64(publicKey); 
      // Construct X509EncodedKeySpec object 
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); 
      // Specified encryption algorithm 
      KeyFactory factory = KeyFactory.getInstance(KEY_RSA); 
      // Obtain public key object 
      PublicKey key = factory.generatePublic(keySpec); 
      // Verify digital signature with public key 
      Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); 
      signature.initVerify(key); 
      signature.update(data); 
      flag = signature.verify(decryptBase64(sign)); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return flag; 
  } 
  /** 
   * Private key decryption 
   * @param data Encrypted data 
   * @param key Private key 
   * @return 
   */ 
  public static byte[] decryptByPrivateKey(byte[] data, String key) { 
    byte[] result = null; 
    try { 
      // Decrypt private key 
      byte[] bytes = decryptBase64(key); 
      // Obtain private key 
      PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); 
      KeyFactory factory = KeyFactory.getInstance(KEY_RSA); 
      PrivateKey privateKey = factory.generatePrivate(keySpec); 
      // Decrypt data 
      Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); 
      cipher.init(Cipher.DECRYPT_MODE, privateKey); 
      result = cipher.doFinal(data); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return result; 
  } 
  /** 
   * Private key decryption 
   * @param data Encrypted data 
   * @param key Public key 
   * @return 
   */ 
  public static byte[] decryptByPublicKey(byte[] data, String key) { 
    byte[] result = null; 
    try { 
      // Decrypt public key 
      byte[] bytes = decryptBase64(key); 
      // Obtain public key 
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); 
      KeyFactory factory = KeyFactory.getInstance(KEY_RSA); 
      PublicKey publicKey = factory.generatePublic(keySpec); 
      // Decrypt data 
      Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); 
      cipher.init(Cipher.DECRYPT_MODE, publicKey); 
      result = cipher.doFinal(data); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return result; 
  } 
  /** 
   * Public key encryption 
   * @param data Data to be encrypted 
   * @param key Public key 
   * @return 
   */ 
  public static byte[] encryptByPublicKey(byte[] data, String key) { 
    byte[] result = null; 
    try { 
      byte[] bytes = decryptBase64(key); 
      // Obtain public key 
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); 
      KeyFactory factory = KeyFactory.getInstance(KEY_RSA); 
      PublicKey publicKey = factory.generatePublic(keySpec); 
      // Encrypt data 
      Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); 
      cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
      result = cipher.doFinal(data); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return result; 
  } 
  /** 
   * Private key encryption 
   * @param data Data to be encrypted 
   * @param key Private key 
   * @return 
   */ 
  public static byte[] encryptByPrivateKey(byte[] data, String key) { 
    byte[] result = null; 
    try { 
      byte[] bytes = decryptBase64(key); 
      // Obtain private key 
      PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); 
      KeyFactory factory = KeyFactory.getInstance(KEY_RSA); 
      PrivateKey privateKey = factory.generatePrivate(keySpec); 
      // Encrypt data 
      Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); 
      cipher.init(Cipher.ENCRYPT_MODE, privateKey); 
      result = cipher.doFinal(data); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return result; 
  } 
  /** 
   * Obtain public key 
   * @param map 
   * @return 
   */ 
  public static String getPublicKey(Map<String, Object> map) { 
    String str = ""; 
    try { 
      Key key = (Key) map.get(KEY_RSA_PUBLICKEY); 
      str = encryptBase64(key.getEncoded()); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return str; 
  } 
  /** 
   * Obtain private key 
   * @param map 
   * @return 
   */ 
  public static String getPrivateKey(Map<String, Object> map) { 
    String str = ""; 
    try { 
      Key key = (Key) map.get(KEY_RSA_PRIVATEKEY); 
      str = encryptBase64(key.getEncoded()); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    return str; 
  } 
  /** 
   * BASE64 Decryption 
   * @param key The string to be decrypted 
   * @return Byte array 
   * @throws Exception 
   */ 
  public static byte[] decryptBase64(String key) throws Exception { 
    return (new BASE64).decodeBuffer(key); 
  } 
  /** 
   * BASE64 Encryption 
   * @param key The byte array to be encrypted 
   * @return String 
   * @throws Exception 
   */ 
  public static String encryptBase64(byte[] key) throws Exception { 
    return (new BASE64).encodeBuffer(key); 
  } 
  /** 
   * Test method 
   * @param args 
   */ 
  public static void main(String[] args) { 
    String privateKey = ""; 
    String publicKey = ""; 
    // Generate public and private keys 
    Map<String, Object> map = init(); 
    publicKey = getPublicKey(map); 
    privateKey = getPrivateKey(map); 
    System.out.println("Public key: \n\r" + publicKey); 
    System.out.println("Private key: \n\r" + privateKey); 
    System.out.println("Public key encryption",--------Private key decryption); 
    String word = "你好,世界!"; 
    byte[] encWord = encryptByPublicKey(word.getBytes(), publicKey); 
    String decWord = new String(decryptByPrivateKey(encWord, privateKey)); 
    System.out.println("Encryption Before: " + word + "\n\r" + "Decrypted: " + decWord); 
    System.out.println("Private key encryption",--------Public key decryption); 
    String english = "Hello, World!"; 
    byte[] encEnglish = encryptByPrivateKey(english.getBytes(), privateKey); 
    String decEnglish = new String(decryptByPublicKey(encEnglish, publicKey)); 
    System.out.println("Encryption Before: " + english + "\n\r" + "Decrypted: " + decEnglish); 
    System.out.println("Private Key Signing - Public Key Verification of Signature"); 
    // Generate Signature 
    String sign = sign(encEnglish, privateKey); 
    System.out.println("Signature:\r" + sign); 
    // Verify Signature 
    boolean status = verify(encEnglish, publicKey, sign); 
    System.out.println("Status:\r" + status); 
  } 
}

Encryption and Decryption Results

Conclusion

In fact, what seems like a complex process can be described in one sentence: using the public key to encrypt and the private key to decrypt completes a data transfer from the party B to the party A. Through private key encryption and public key decryption, and at the same time through private key signing and public key verification of the signature, a data transfer and verification from the party A to the party B is completed. Two data transfers complete a set of data interactions.

The emergence of asymmetric encryption algorithms is to solve the problem of encryption and decryption with only one key. If this key is lost or made public, the encrypted data is easily attacked. At the same time, it is precisely because of the emergence of asymmetric encryption algorithms that digital signatures, digital certificates, and so on came into being.

Alright, that's all for today. The next article will continue with asymmetric encryption. As to which one, we will know later. For now, let's keep it a secret.

Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (Please replace # with @ when sending an email to report violations, and provide relevant evidence. Once verified, this site will immediately delete the infringing content.)

You May Also Like