单向散列加密、对称加密与非对称加密

单向散列加密

  1. 是什么?
    散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。
  2. 适用场景
    单向散列函数一般用于产生消息摘要,密钥加密等.
  3. 常见的加密算法
  • MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法,非可逆,相同的明文产生相同的密文。标准密钥长度128位.
  • SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值. 标准密钥长度160位.
  • md4
  • CRC-32
    SHA-1与MD5的比较:
    因为二者均由MD4导出,SHA-1和MD5彼此很相似。相应的,他们的强度和其他特性也是相似.
    但还有以下几点不同:
  • 对强行攻击的安全性:最显著和最重要的区别是SHA-1摘要比MD5摘要长32 位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2128数量级的操作,而对SHA-1则是2160数量级的操作。这样,SHA-1对强行攻击有更大的强度。
  • 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。
  • 速度:在相同的硬件上,SHA-1的运行速度比MD5慢。
  1. 特征:雪崩效应、定长输出和不可逆。
  2. 作用:确保数据的完整性。
  3. 加密工具:md5sum、sha1sum和openssl dgst。
  4. 计算某个文件的hash值,例如:md5sum/shalsum FileName, openssl dgst –md5/-sha.
  5. 代码实现(md5)
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.StringUtils;

import java.security.MessageDigest;
import java.util.Random;

/**
 * 加盐MD5加密
 */
public class PasswordUtil {
    /**
     * 生成含有随机盐的密码
     */
    public static String generate(String password) {
        Random r = new Random();
        StringBuilder sb = new StringBuilder(16);
        sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));

        String salt = StringUtils.rightPad(sb.toString(), 16, "0");
        password = md5Hex(password + salt);
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return new String(cs);
    }

    /**
     * 校验密码是否正确
     */
    public static boolean verify(String password, String md5) {
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md5.charAt(i);
            cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
            cs2[i / 3] = md5.charAt(i + 1);
        }
        String salt = new String(cs2);
        return md5Hex(password + salt).equals(new String(cs1));
    }

    /**
     * 获取十六进制字符串形式的MD5摘要
     */
    public static String md5Hex(String src) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bs = md5.digest(src.getBytes());
            return new String(new Hex().encode(bs));
        } catch (Exception e) {
            return null;
        }
    }

    public static void main(String[] args) {
        // 加密+加盐
        String password1 = generate("admin123456789100000");
        System.out.println("结果:" + password1 + "   长度:" + password1.length());
        // 解码
        System.out.println(verify("admin123456789100000", password1));
    }
}

对称加密

  1. 是什么?
    发件人和收件人使用其共同拥有的单个密钥 ,这种密钥既用于加密,也用于解密,叫做机密密钥(也称为对称密钥或会话密钥)。
    能够提供信息机密性(没有密钥信息不能被解密)、完整性(被改变的信息不能被解密)的服务。
    对称式密码学又称:单钥密码学、秘密密钥密码学、会话密钥密码学、私钥密码学、共享秘钥密码学.
  2. 常见的对称式加密技术
  • DES(数据加密标准):分组式加密,算法源于Lucifer,作为NIST对称式加密标准;64位(有效位56位、校验8位),分组算法.
  • 3DES:128位,分组算法.
  • IDEA(国际数据加密算法):128位,比DES快,分组算法.
  • Blowfish:32-448位,算法公开,分组算法.
  • RC4:流密码,密钥长度可变.
  • RC5:分组密码,密钥长度可变,最大2048位.
  • Rijndael:128位/196位/256位.
  • AES(高级加密标准):DES升级版,算法出自Rinjindael.
  1. 优点
    用户只需记忆一个密钥,就可用于加密、解密;
    与非对称加密方法相比,加密解密的计算量小,速度快,简单易用,适合于对海量数据进行加密处理 。
  2. 缺点
    如果密钥交换不安全,密钥的安全性就会丧失。特别是在电子商务环境下,当客户是未知的、不可信的实体时,如何使客户安全地获得密钥就成为一大难题。
  3. 适用场景
    一般用于服务器与服务器之前的通讯.
  4. 代码实现(基于DES实现加密和解密)
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
 * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
 * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。
 * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数
 */
public class DesUtils {

    /**
     * 加密
     *
     * @param datasource
     * @param secretKey
     * @return
     */
    public static String encrypt(byte[] datasource, String secretKey) throws Exception {
        byte[] bytes = operation(datasource, secretKey, Cipher.ENCRYPT_MODE);
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bytes);
    }

    private static byte[] operation(byte[] inputBuffer, String secretKey, int operationMode) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(secretKey.getBytes());
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES");
        // 用密钥初始化Cipher对象
        cipher.init(operationMode, securekey, random);
        // 真正开始解密操作
        return cipher.doFinal(inputBuffer);
    }

    /**
     * 解密
     *
     * @param src
     * @param secretKey
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(String src, String secretKey) throws Exception {
        BASE64Decoder decoder = new BASE64Decoder();
        return operation(decoder.decodeBuffer(src), secretKey, Cipher.DECRYPT_MODE);
    }

    // 测试
    public static void main(String args[]) throws Exception {
        // 待加密内容
        String str = "abc123&&";
        // 密钥随意定, 长度要是8的倍数
        String password = "12345678";
        String encrypt = encrypt(str.getBytes(), password);
        System.out.println("加密后:" + encrypt);
        // 解密
        byte[] decrypt = decrypt(encrypt, password);
        System.out.println("解密后:" + new String(decrypt, "utf-8"));
    }
}

非对称加密

  1. 是什么?
    使用一对密钥:一个用于加密信息,另一个则用于解密信息。
    其中加密密钥不同于解密密钥, 公钥加密私钥解密; 反之, 私钥加密公钥解密。
    密钥依据性质划分,将其中的一个向外界公开,称为公钥;另一个则自己保留,称为私钥。公钥(Public key)常用于数据加密(用对方公钥加密)或签名验证(用对方公钥解密),私钥(Private key)常用于数据解密或数字签名。
    具有机密性、完整性和抗抵赖性.
  2. 常用算法
    RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)
  3. 优点: 难破解
  4. 缺点: 加密速度慢
  5. 适用场景
    一般用于客户端与服务器之前的通讯.
  6. 代码实现(RSA 工具类)
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

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;

/**
 * RSA加解密工具类
 */
@Slf4j
public class RsaUtils {

    // 公钥
    public static String publicKey;

    // 私钥
    public static String privateKey;

    static {
        generateKey();
    }

    /**
     * 生成公钥和私钥
     */
    public static void generateKey() {
        // 1.初始化秘钥
        KeyPairGenerator keyPairGenerator;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            // 随机数生成器
            SecureRandom sr = new SecureRandom();
            // 设置512位长的秘钥
            keyPairGenerator.initialize(512, sr);
            // 开始创建
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 进行转码
            publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
            // 进行转码
            privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            log.error("生成公钥和私钥, 错误信息", e);
        }
    }

    /**
     * 公钥匙加密(或解密)
     *
     * @param content
     * @param publicKeyStr
     * @param operationMode
     * @return
     */
    public static String encryptByPublicKey(String content, String publicKeyStr, int operationMode) {
        // 公钥要用X509进行处理
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
        KeyFactory keyFactory;
        PublicKey publicKey;
        Cipher cipher;
        byte[] result;
        String text = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            // 还原Key对象
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(operationMode, publicKey);
            // 加密
            if (operationMode == Cipher.ENCRYPT_MODE) {
                result = cipher.doFinal(content.getBytes());
                text = Base64.encodeBase64String(result);
            } else if (operationMode == Cipher.DECRYPT_MODE) {
                // 解密
                result = cipher.doFinal(Base64.decodeBase64(content));
                text = new String(result, "UTF-8");
            }
        } catch (Exception e) {
            log.error("公钥匙加密(或解密), 错误信息", e);
        }
        return text;
    }

    /**
     * 私钥匙解密(或加密)
     *
     * @param content
     * @param privateKeyStr
     * @param operationMode
     * @return
     */
    public static String decryptByPrivateKey(String content, String privateKeyStr, int operationMode) {
        // 私钥要用PKCS8进行处理
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
        KeyFactory keyFactory;
        PrivateKey privateKey;
        Cipher cipher;
        byte[] result;
        String text = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            // 还原Key对象
            privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(operationMode, privateKey);
            // 加密
            if (operationMode == Cipher.ENCRYPT_MODE) {
                result = cipher.doFinal(content.getBytes());
                text = Base64.encodeBase64String(result);
            } else if (operationMode == Cipher.DECRYPT_MODE) {
                // 解密
                result = cipher.doFinal(Base64.decodeBase64(content));
                text = new String(result, "UTF-8");
            }
        } catch (Exception e) {
            log.error("私钥匙解密(或加密), 错误信息", e);
        }
        return text;
    }

    // 测试方法
    public static void main(String[] args) {
        // 注意:公钥加密必须私钥解密, 私钥加密必须公钥解密
        System.out.println("公钥给发送方: " + RsaUtils.publicKey);
        System.out.println("私钥给接收方: " + RsaUtils.privateKey);

        // 公钥加密(常用)
        String content = "你吃了吗? O(∩_∩)O~";
        String sendContent = RsaUtils.encryptByPublicKey(content, RsaUtils.publicKey, Cipher.ENCRYPT_MODE);
        System.out.println("内容用公钥加密后:" + sendContent);

        // 私钥解密(常用)
        String decryptedContent = RsaUtils.decryptByPrivateKey(sendContent, RsaUtils.privateKey, Cipher.DECRYPT_MODE);
        System.out.println("内容用私钥解密后:" + decryptedContent);

        // 私钥加密
        String content2 = "还没, O(∩_∩)O~";
        String sendContent2 = RsaUtils.decryptByPrivateKey(content2, RsaUtils.privateKey, Cipher.ENCRYPT_MODE);
        System.out.println("内容用私钥加密后:" + sendContent2);

        // 公钥解密
        String decryptedContent2 = RsaUtils.encryptByPublicKey(sendContent2, RsaUtils.publicKey, Cipher.DECRYPT_MODE);
        System.out.println("内容用公钥解密后:" + decryptedContent2);
    }

}

url转码与解码

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * url请求参数需要转码, 避免发生意想不到的结果
 */
public class UrlUtils {

    public static void main(String[] args) throws UnsupportedEncodingException {
        String url = "http://127.0.0.1:8080/tranIndex?";
        // url请求参数转码
        String strParam = "name=" + URLEncoder.encode("1+1", "utf-8");
        String newUrl = url + strParam;
        System.out.println("请求地址: " + newUrl);
    }
}

小技巧

  1. 重定向适用于请求外部资源, 转发适用于请求本服务的资源.
  2. 抓包工具可以拦截同一网段的请求.
  3. 验签可以检查请求参数是否被篡改, Token也可以防篡改(重定向使用参数令牌来调接口).
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值