Java与对称加密、非对称加密算法

对数据加密的算法有很多种。总体来说分为两大类:对称加密算法和非对称加密算法。

对称加密算法

对称加密算法要求加密与解密使用同一个共享密钥。解密算法是加密算法的逆运算,加密密钥和解密密钥相同。
对称加密的工作原理如下:

Java与对称加密、非对称加密算法_第1张图片

其中,对称加密算法有两种主要的方式:

  • 流密码:对明文的单个位进行运算,转换为密文的单个位。
  • 分组密码:将明文划分成不同的组,分别对每个组进行加密解密。

平常使用时,分组密码是最常用的。分组密码根据数据加密时每个加密区块间的关联方式来区分,可以分为4种工作模式:

  • 电子密码本模式-ECB
  • 密文链接模式-CBC
  • 密文反馈模式-CFB
  • 输出反馈模式-OFB

在Java的编码实现时,需要指定相应的工作模式。关于选择何种模式,可以参考这篇博客
另外,分组密码有三种填充方式:

  • NoPadding:不填充。
  • ZerosPadding:全部填充为0。
  • PKCS5Padding:每个填充的字节都记录了填充的总字节数。

一般而言,会选择PKCS5Padding的方式。
对称加密有三种常用的算法:DES 3DES AES。以下是各个算法的比较:

Java与对称加密、非对称加密算法_第2张图片

下面是DES算法的Java实现:

import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class DesEncrypt {

    public static final String KEY_ALGORITHM = "DES";
    public static final String CIPHER_ALGORIGHM = "DES/ECB/PKCS5Padding";
    public static final int KEY_LENGTH = 56;
    private static final Charset CHARSET = Charset.forName("UTF-8");

    /**
     * 获取Key
     * @param key 指定的密钥
     * @return 生成的Key
     */
    public Key getKey(byte[] key) {
        try {
            if (key == null || key.length == 0) {
                KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
                keyGenerator.init(KEY_LENGTH);
                SecretKey secretKey = keyGenerator.generateKey();
                key = secretKey.getEncoded();
            }
            DESKeySpec desKeySpec = new DESKeySpec(key);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
            return keyFactory.generateSecret(desKeySpec);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 加密
     * @param data 要加密的数据
     * @param key  密钥
     * @return 加密后的数据
     */
    public byte[] encrypt(byte[] data, Key key) {
        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORIGHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(data);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     * @param data 要解密的密文
     * @param key  密钥
     * @return    解密后的数据
     */
    public byte[] decrypt(byte[] data, Key key) {
        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORIGHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(data);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
}

非对称加密算法

非对称加密算法分为两个密钥,一个公开,一个保密。公开的密钥称为公钥,保密的密钥称为私钥。私钥加密的数据必须公钥解密,公钥加密的数据必须私钥解密。
工作原理如下:

Java与对称加密、非对称加密算法_第3张图片

注意的是:公钥加密的数据,必须用私钥解密;私钥加密的数据,必须用公钥解密。
常用的非对称加密算法是RSA。

下面是RSA的实现:

import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.Key;
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.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA加密解密
 */

public class RSAAlgorithm {
    public static final String KEY_ALGORITHM = "RSA";
    private static final int KEY_SIZE = 512;

    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private KeyPair keyPair;
    private byte[] data;

    public RSAAlgorithm(String data) {
        this(data.getBytes(DEFAULT_CHARSET));
    }

    public RSAAlgorithm(byte[] data) {
        this.data = data;
        generateKey();
    }

    public void generateKey() {
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(KEY_SIZE);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    //获取公钥
    public Key getPublicKey() {
        return keyPair.getPublic();
    }

    //获取私钥
    public Key getPrivateKey() {
        return keyPair.getPrivate();
    }

    //私钥加密
    public byte[] encryptByPrivateKey() {
        try{
            byte[] key = getPrivateKey().getEncoded();
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            return cipher.doFinal(data);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    //私钥解密
    public byte[] decryptByPrivateKey() {
        try {
            byte[] key = getPrivateKey().getEncoded();
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return cipher.doFinal(data);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    //公钥加密
    public byte[] encryptByPublicKey() {
        try {
            byte[] key = getPublicKey().getEncoded();
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(data);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    //公钥解密
    public byte[] decryptByPublicKey() {
        try {
            byte[] key = getPublicKey().getEncoded();
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            return cipher.doFinal(data);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

}

总结

如果要使用对称加密算法,建议采用AES算法,不管从性能还是安全性来说,都有很大的优势。非对称加密算法当然不止RSA一种,但是RSA是我们接触最多的,安全性也很好。非对称加密比对称加密的安全性要高,但是运算速度相比较低。

你可能感兴趣的:(Java)