一、对称加密算法 

加密和解密使用相同密钥的加密算法。常用的算法包括DES、3DES、AES、DESX、Blowfish、RC4、RC5、RC6。


DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合。


3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高。


AES(Advanced Encryption Standard):高级加密标准,速度快,安全级别高【128位秘钥】;


二、非对称加密算法

加密和解密使用不同密钥的加密算法,也称为公私钥加密。常见的算法包括RSA、DSA(数字签名用)、ECC(移动设备用)、Diffie-Hellman、El Gamal。


RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的;【建议1024位秘钥】

DSA:数字签名算法,是一种标准的 DSS(数字签名标准)

ECC:椭圆曲线密码编码学【建议160位秘钥】。


ECC VS RSA

1)抗攻击性强。相同的密钥长度,其抗攻击性要强很多倍。

2)计算量小,处理速度快。ECC总的速度比RSA、DSA要快得多。

3)存储空间占用小。ECC的密钥尺寸和系统参数与RSA、DSA相比要小得多,意味着它所占的存贮空间要小得多。这对于加密算法在IC卡上的应用具有特别重要的意义。

4)带宽要求低。当对长消息进行加解密时,三类密码系统有相同的带宽要求,但应用于短消息时ECC带宽要求却低得多。带宽要求低使ECC在无线网络领域具有广泛的应用前景。


三、散列算法

除法散列法 平方散列法 斐波那契(Fibonacci)散列法 随机数法


单向散列函数一般用于产生消息摘要,密钥加密等,常用的算法包括MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1。


MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法,非可逆,相同的明文产生相同的密文。


SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值;


SHA-1 VS MD5 [二者均由MD4导出]

1)SHA-1摘要比MD5摘要长32位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2^(128)数量级的操作,而对SHA-1则是2^(160)数量级的操作。这样,SHA-1对强行攻击有更大的强度。

2)MD5易受密码分析的攻击,SHA-1显得不易受这样的攻击。

3)在相同的硬件上,SHA-1的运行速度比MD5慢。


四、加密算法的选择

1.单方密码存储建议直接使用散列算法(MD5即可,配合密码更新策略)。


2.内部信息加密传输建议使用对称加密效率跟高(AES)。


3.外部数据传输建议使用非对称加密,秘钥保存更安全(RSA)。


4.HTTPS高级用法:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。


五、上源码

5.1 AES对称加密

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.codec.binary.Base64;

import org.apache.commons.lang3.ArrayUtils;

import org.springframework.util.StringUtils;

 

import javax.crypto.Cipher;

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;

 

/**

 * <p>

 * AES加密工具

 * </p>

 *

 * @author ocean

 * @version 1.0.0

 * @date 2023/5/4 14:51

 */

@Slf4j

public class AESUtils {

 

    // 秘钥 16

    private static final String SECRET_KEY = "1111111111111111";

    // 秘钥 24

    //private static final String SECRET_KEY = "111111111111111122222222";

    // 秘钥 32

    //private static final String SECRET_KEY = "11111111111111112222222233333333";

 

    // 算法

    private static final String ALGORITHM = "AES";

 

    private static final String UTF8 = StandardCharsets.UTF_8.name();

 

    /**

     * 字符串加密

     *

     * @param message   明文字符串

     * @param secretKey 秘钥

     * @return 加密字符串

     */

    public static String encryption(String message, String secretKey) {

        if (!StringUtils.hasLength(message)) {

            log.error("encryption message should not be null or empty.");

        }

        byte[] encodeBytes = encryption(message.getBytes(StandardCharsets.UTF_8), secretKey);

        return Base64.encodeBase64String(encodeBytes);

    }

 

    /**

     * 字符串加密

     *

     * @param messageBytes 明文字节数组

     * @param secretKey    秘钥

     * @return 加密字节数组

     */

    public static byte[] encryption(byte[] messageBytes, String secretKey) {

        if (ArrayUtils.isEmpty(messageBytes)) {

            log.error("encryption message should not be empty.");

        }

        if (!StringUtils.hasLength(secretKey)) {

            log.error("secretKey {}, encryption key should not be null or empty.", secretKey);

        }

        Cipher cipher = getCipher(secretKey, Cipher.ENCRYPT_MODE);

        byte[] encryptionBytes = null;

        try {

            encryptionBytes = cipher.doFinal(messageBytes);

        } catch (Exception e) {

            log.error("encryption fail. ", e);

        }

        return encryptionBytes;

    }

 

    /**

     * 字符串加密

     *

     * @param encryptionMessage 加密字符串

     * @param secretKey         秘钥

     * @return 明文字符串

     */

    public static String decrypt(String encryptionMessage, String secretKey) {

        if (!StringUtils.hasLength(encryptionMessage)) {

            log.error("decrypt encryptionMessage should not be null or empty.");

        }

        byte[] decodeBytes = decrypt(Base64.decodeBase64(encryptionMessage.getBytes(StandardCharsets.UTF_8)), secretKey);

        return new String(decodeBytes, StandardCharsets.UTF_8);

    }

 

 

    /**

     * 字符串加密

     *

     * @param encryptedBytes 加密字节数组

     * @param secretKey      秘钥

     * @return 明文字节数组

     */

    public static byte[] decrypt(byte[] encryptedBytes, String secretKey) {

        if (ArrayUtils.isEmpty(encryptedBytes)) {

            log.error("decrypt encryptedBytes should not be empty.");

        }

        if (!StringUtils.hasLength(secretKey)) {

            log.error("secretKey {}, decrypt key should not be null or empty.", secretKey);

        }

        Cipher cipher = getCipher(secretKey, Cipher.DECRYPT_MODE);

        byte[] decodeBytes = null;

        try {

            decodeBytes = cipher.doFinal(encryptedBytes);

        } catch (Exception e) {

            log.error("decrypt fail. ", e);

        }

        return decodeBytes;

    }

 

    private static Cipher getCipher(String key, int mode) {

        Cipher cipher = null;

        SecretKey secretKey;

        try {

            cipher = Cipher.getInstance(ALGORITHM);

            byte[] keyBytes = key.getBytes(UTF8);

            secretKey = new SecretKeySpec(keyBytes, ALGORITHM);

            cipher.init(mode, secretKey);

        } catch (Exception e) {

            log.error("getAESCipher fail. ", e);

        }

        return cipher;

    }

 

    public static void main(String[] args) {

        String data = "ocean测试!@#";

        log.info("AES秘钥长度只能为16、24、32:{}", SECRET_KEY.getBytes(StandardCharsets.UTF_8).length);

        String encryptionData = encryption(data, SECRET_KEY);

        log.info("加密后:{}", encryptionData);

        String decryptData = decrypt(encryptionData, SECRET_KEY);

        log.info("解密后:{}", decryptData);

    }

 

 

}

5.2 RSA非对称加密

PSCK#8 – PSCK#1

<!– https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on –>

<dependency>

<groupId>org.bouncycastle</groupId>

<artifactId>bcprov-jdk15on</artifactId>

<version>1.52</version>

</dependency>

import java.io.StringWriter;

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.Signature;

import java.security.interfaces.RSAPrivateKey;

import java.security.interfaces.RSAPublicKey;

import java.security.spec.InvalidKeySpecException;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

 

import javax.crypto.Cipher;

 

import org.apache.commons.codec.binary.Base64;

import org.bouncycastle.asn1.ASN1Encodable;

import org.bouncycastle.asn1.ASN1Primitive;

import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;

import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;

import org.bouncycastle.util.io.pem.PemObject;

import org.bouncycastle.util.io.pem.PemWriter;

 

import sun.misc.BASE64Decoder;

import sun.misc.BASE64Encoder;

 

public class RsaUtils {

 

public static final int KEY_SIZE = 2048;

public static final String ALGORITHM = "RSA";

 

 

public static final String PUBLIC_KEY = "xxxxpublicKeyxxxx";

public static final String PRIVATE_KEY = "xxxxprivateKeyxxxx";

 

public static final String CLEAR_TEXT_STRING = "明文字符串";

 

public static BASE64Encoder encoder = new BASE64Encoder();

public static BASE64Decoder decoder = new BASE64Decoder();

 

public static void main(String[] args) throws Exception {

// PSCK#8

Map<String, String> keyMap = RsaUtil.generateKeyBytes();

System.out.println("PSCK#8-PRIVATEKEY:"+ keyMap.get(RsaUtil.PRIVATE_KEY));

System.out.println("PSCK#8-PUBLICKEY:" + keyMap.get(RsaUtil.PUBLIC_KEY));

PublicKey publicKey8 = RsaUtil.restorePublicKey(keyMap.get(RsaUtil.PUBLIC_KEY));

PrivateKey privateKey8 = RsaUtil.restorePrivateKey(keyMap.get(RsaUtil.PRIVATE_KEY));

 

// ============公钥加密-私钥解密============

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.ENCRYPT_MODE, publicKey8);

String messageEn = Base64.encodeBase64String(cipher.doFinal(CLEAR_TEXT_STRING.getBytes("UTF-8")));

System.out.println(CLEAR_TEXT_STRING + "\t加密后的字符串为:" + messageEn);

cipher.init(Cipher.DECRYPT_MODE, privateKey8);

String messageDe = new String(cipher.doFinal(Base64.decodeBase64(messageEn.getBytes("UTF-8"))));

System.out.println("还原后的字符串为:" + messageDe);

// ============公钥加密-私钥解密============

 

 

// ============PSCK#8>PSCK#1============

byte[] privBytes = privateKey8.getEncoded();

PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);

ASN1Encodable encodable = pkInfo.getPrivateKey();

ASN1Primitive primitive = encodable.toASN1Primitive();

 

byte[] privateKeyPKCS1 = primitive.getEncoded();

PemObject pemObject = new PemObject("RSA PRIVATE KEY", privateKeyPKCS1);

StringWriter stringWriter = new StringWriter();

PemWriter pemWriter = new PemWriter(stringWriter);

pemWriter.writeObject(pemObject);

pemWriter.close();

String pemString = stringWriter.toString();

System.out.println("PSCK#1-PRIVATEKEY:" + pemString);

 

byte[] pubBytes = publicKey8.getEncoded();

SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo

.getInstance(pubBytes);

ASN1Primitive punlic = spkInfo.parsePublicKey();

byte[] publicKeyPKCS1 = punlic.getEncoded();

 

PemObject punlicpemObject = new PemObject("RSA PUBLIC KEY",

publicKeyPKCS1);

StringWriter punlicstringWriter = new StringWriter();

PemWriter punlicpemWriter = new PemWriter(punlicstringWriter);

punlicpemWriter.writeObject(punlicpemObject);

punlicpemWriter.close();

String publicemString = punlicstringWriter.toString();

System.out.println("PSCK#8-PUBLICKEY:" + publicemString);

// ============PSCK#8>PSCK#1============

 

// ============私钥签名公钥验签============

// PSCK#8-PRIVATEKEY 私钥签名

Signature signature = Signature.getInstance("SHA256WithRSA");

signature.initSign(privateKey8);

signature.update(CLEAR_TEXT_STRING.getBytes());

byte[] signed = signature.sign();

String sign = encoder.encode(signed);

 

// PSCK#8-PUBLICKEY 公钥验签

signature.initVerify(publicKey8);

signature.update(CLEAR_TEXT_STRING.getBytes());

boolean verify = signature.verify(decoder.decodeBuffer(sign));

 

System.out.println("CLEAR_TEXT_STRING:" + CLEAR_TEXT_STRING);

System.out.println("SIGN:" + sign.replaceAll("\r|\n", ""));

System.out.println(verify);

// ============私钥签名公钥验签============

}

 

/**

* 公私钥生成

* @return

*/

public static Map<String, String> generateKeyBytes() {

try {

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);

keyPairGenerator.initialize(KEY_SIZE);

KeyPair keyPair = keyPairGenerator.generateKeyPair();

 

RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

 

Map<String, String> keyMap = new HashMap<String, String>();

keyMap.put(PUBLIC_KEY, new String(Base64.encodeBase64(publicKey.getEncoded())));

keyMap.put(PRIVATE_KEY, new String(Base64.encodeBase64(privateKey.getEncoded())));

return keyMap;

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

}

return null;

}

/**

* 公钥生成

* @param key

* @return

*/

public static PublicKey restorePublicKey(String key) {

X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));

try {

KeyFactory factory = KeyFactory.getInstance(ALGORITHM);

PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec);

return publicKey;

} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {

e.printStackTrace();

}

return null;

}

/**

* 私钥生成

* @param key

* @return

*/

    public static PrivateKey restorePrivateKey(String key) {

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));

        try {

            KeyFactory factory = KeyFactory.getInstance(ALGORITHM);

            PrivateKey privateKey = factory

                    .generatePrivate(pkcs8EncodedKeySpec);

            return privateKey;

        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {

            e.printStackTrace();

        }

        return null;

    }

 

}

5.3 MD5散列算法

import lombok.extern.slf4j.Slf4j;

 

import java.security.MessageDigest;

 

 

@Slf4j

public class MD5Util {

    public static final int SIZE_FACTOR = 2;

    private static final String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

 

    public static String MD5Encode(String origin, String charsetname) {

        String resultString = null;

        try {

            resultString = origin;

            MessageDigest md = MessageDigest.getInstance("MD5");

            if (charsetname == null || "".equals(charsetname)) {

                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));

            } else {

                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));

            }

        } catch (Exception exception) {

            log.error("MD5Util MD5Encode error", exception);

        }

        return resultString;

    }

 

    private static String byteArrayToHexString(byte[] b) {

        StringBuffer resultSb = new StringBuffer();

        for (int i = 0; i < b.length; i++) {

            resultSb.append(byteToHexString(b[i]));

        }

        return resultSb.toString();

    }

 

    private static String byteToHexString(byte b) {

        int n = b;

        if (n < 0) {

            n += 256;

        }

        int d1 = n / 16;

        int d2 = n % 16;

        return hexDigits[d1] + hexDigits[d2];

    }

 

    public static String encode(String str) {

        try {

            byte[] hash = MessageDigest.getInstance("MD5").digest(str.getBytes("utf-8"));

            StringBuilder hex = new StringBuilder(hash.length * SIZE_FACTOR);

            for (byte b : hash) {

                hex.append(String.format("%02x", b));

            }

            return hex.toString();

        } catch (Exception e) {

            log.error("MD5 encode error for {}, error is {}", str, e.getMessage(), e);

        }

        return null;

    }

}


————————————————

版权声明:本文为CSDN博主「Ocean@上源码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_34253002/article/details/131491945