常用加密
  DPhgMOoXTXDH 2023年11月02日 55 0

密码学

概述

  1. 散列函数

散列函数,也见杂凑函数、摘要函数或哈希函数,可将任意长度的消息经过运算,变成固定长度数值,常见的有MD5、SHA-1、SHA256,多应用在文件校验,数字签名中。

MD5 可以将任意长度的原文生成一个128位(16字节)的哈希值

SHA-1可以将任意长度的原文生成一个160位(20字节)的哈希值

  1. 对称密码

对称密码应用了相同的加密密钥和解密密钥。对称密码分为:序列密码(流密码),分组密码(块密码)两种。流密码是对信息流中的每一个元素(一个字母或一个比特)作为基本的处理单元进行加密,块密码是先对信息流分块,再对每一块分别加密。

例如原文为1234567890,流加密即先对1进行加密,再对2进行加密,再对3进行加密……最后拼接成密文;块加密先分成不同的块,如1234成块,5678成块,90XX(XX为补位数字)成块,再分别对不同块进行加密,最后拼接成密文。前文提到的古典密码学加密方法,都属于流加密。

  1. 非对称密码

对称密码的密钥安全极其重要,加密者和解密者需要提前协商密钥,并各自确保密钥的安全性,一但密钥泄露,即使算法是安全的也无法保障原文信息的私密性。

在实际的使用中,远程的提前协商密钥不容易实现,即使协商好,在远程传输过程中也容易被他人获取,因此非对称密钥此时就凸显出了优势。

非对称密码有两支密钥,公钥(publickey)和私钥(privatekey),加密和解密运算使用的密钥不同。用公钥对原文进行加密后,需要由私钥进行解密;用私钥对原文进行加密后(此时一般称为签名),需要由公钥进行解密(此时一般称为验签)。公钥可以公开的,大家使用公钥对信息进行加密,再发送给私钥的持有者,私钥持有者使用私钥对信息进行解密,获得信息原文。因为私钥只有单一人持有,因此不用担心被他人解密获取信息原文。

  1. base64

Base64就是一种基于64个可打印字符来表示二进制数据的方法。

Base64编码是从二进制到字符的过程

在项目中,将报文进行压缩、加密后,最后一步必然是使用base64编码,因为base64编码的字符串,更适合不同平台、不同语言的传输。

BASE64是编码, 不是压缩, 编码后只会增加字节数;(比之前多3分之一)
 算法简单, 几乎不会影响效率;
 算法可逆, 解码很方便, 不用于私密信息通信;
 加密后的字符串只有[0-9a-zA-Z+/=], 不可打印字符(包括转移字符)也可传输;

  1. 数字签名

A发送消息给B:A(不可抵赖)——————>B(不可伪造)(不可重用)
(1)不可抵赖 (假如:A可以否认发过该消息,B无法证明A确实发了该消息)
(2)不可伪造 (假如:B伪造一个不同的消息,但声称是从A收到的)
(3)不可重用 (假如:签名没有和消息绑定)

传统笔迹签名:
一般认为,传统的手写签名具有以下特点:
1)手写签名是“不可伪造”的
2)手写签名是“不可抵赖”的
3)手写签名是“不可重用”的
数字签名至少应该具有这些能力

  1. 消息摘要:

消息摘要:Message Digest,又称为数字摘要(Digital Digest),要高大上还可以将其叫为:单向散列函数(one-way hash function)、哈希函数、杂凑函数等。消息摘要是一个唯一对应一个消息的固定长度的值,由一个单向哈希加密函数对消息进行计算而得到。通俗点说,无论是什么消息、无论什么时间、什么地点,只要采用同样的计算规则(算法),得到的结果都是一样的;并且无论消息长还是短,同一个算法计算得到的长度都是固定的。

从上面的描述可以看出消息摘要的特点:

1)只要消息不同,对其摘要后产生的结果也不同;
2)相同的消息一定会得到相同的结果;
3)无论消息的长短,计算出来的消息摘要长度是固定的;例如:
MD5 摘要后的长度为 128 个bit;
SHA-1 摘要后的长度为 160 个bit;
4)消息摘要算法是单向的,不可逆。

常见的消息摘要算法有: MD5、SHA-1、SHA-256、SHA-512,其他还有 MD4、SHA-2、SHA-224、SHA-384 等。

加密的代码实现

散列函数

md5:

md5,其实就是一中算法。可以将一个字符串,或文件,或压缩包,执行md5后,就可以生成一个固定长度为128bit的串。这个串,基本上是唯一的。把一个任意长度的字节串变换成⼀定⻓度的⼗六进制数字串。 默认为128bit,也就是128个0和1的二进制串。这样表达是很不友好。所以将二进制转成了16进制,每4个bit表示一个16进制所以128/4 = 32 换成16进制表示后,为32位了。

Java md5 代码测试:

DigestUtils 全类名为 org.apache.commons.codec.digest.DigestUtils;

@org.junit.Test
    public void md5test(){
        String name = "hello world";
        String encode = DigestUtils.md5Hex(name);
        System.out.println( encode+","+encode.length());//5eb63bbbe01eeed093cb22bb8f5acdc3,32
    }

SHA-1

SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。 【维基百科】

@org.junit.Test
    public void sha1test(){
        String name = "hello world";
        String encode = DigestUtils.sha1Hex(name);
        System.out.println( encode+","+encode.length());//2aae6c35c94fcfb415dbe95f408b9ce91ee846ed,40
    }

对称加密

DES

返回结果:

jdk des encrypt:70a5396f60b0ccd35ce507382664fb93
jdk des decrypt:hello world

@org.junit.Test
    public  void jdkDES() {
        String string = "hello world";
        try {

            // 生成key//返回生成指定算法密钥的KeyGenerator对象
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56);//初始化此密钥生成器,使其具有确定的密钥大小
            SecretKey secretKey = keyGenerator.generateKey();//生成一个密钥
            byte[] bs = secretKey.getEncoded();

            // key转换
            DESKeySpec desKeySpec = new DESKeySpec(bs); //实例化DES密钥规则
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DES"); //实例化密钥工厂
            Key convertSecretKey = factory.generateSecret(desKeySpec); //生成密钥

            // 加密
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(string.getBytes());
            System.out.println("jdk des encrypt:" + Hex.encodeHexString(result));

            // 解密
            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("jdk des decrypt:" + new String(result));
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

AES:

jdk aes encrypt:[B@76f2b07d
jdk aes decrypt:hello world

@org.junit.Test
    public  void jdkAES() {
        String string = "hello world";
        try {

            // 根据指定的 RNG 算法, 创建安全随机数生成器
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            // 设置 密钥key的字节数组 作为安全随机数生成器的种子
            random.setSeed(string.getBytes());

            // 创建 AES算法生成器
            KeyGenerator gen = KeyGenerator.getInstance("AES");
            // 初始化算法生成器
            gen.init(128);
            SecretKey secretKey = gen.generateKey();

            // 获取 AES 密码器
            Cipher cipher = Cipher.getInstance("AES");
            // 初始化密码器(加密模型)
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            // 加密
            byte[] result = cipher.doFinal(string.getBytes());
            System.out.println("jdk aes encrypt:" +result);

            // 解密
            // 初始化密码器(解密模型)
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            result = cipher.doFinal(result);
            System.out.println("jdk aes decrypt:" + new String(result));
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

非对称加密

RSA

公钥加密,私钥解密

私钥:[B@2cfb4a64
公钥:[B@5474c6c
jdk rsa encrypt:[B@184f6be2
jdk rsa decrypt:hello world

@org.junit.Test
    public void jdkRSA() {
        try {
            String string = "hello world";
            KeyPair generator = KeyPairGenerator.getInstance("RSA").generateKeyPair();
            RSAPrivateKey privateKey = (RSAPrivateKey) generator.getPrivate();
            RSAPublicKey publicKey = (RSAPublicKey) generator.getPublic();

            String privateKeyStr = String.valueOf(Base64.encode(privateKey.getEncoded()));
            String publicKeyStr = String.valueOf(Base64.encode(publicKey.getEncoded()));

            System.out.println("私钥:" + privateKeyStr);
            System.out.println("公钥:" + publicKeyStr);

            // 获取 RSA 密码器

            Cipher cipher = Cipher.getInstance("RSA");
            // 初始化密码器(加密模型)
            cipher.init(Cipher.ENCRYPT_MODE, (RSAPublicKey) generator.getPublic());

            byte[] result = cipher.doFinal(string.getBytes("UTF-8"));
            System.out.println("jdk rsa encrypt:" + result);
            cipher.init(Cipher.DECRYPT_MODE, (RSAPrivateKey) generator.getPrivate());
            result = cipher.doFinal(result);
            System.out.println("jdk rsa decrypt:" + new String(result));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }

    }

base64

使用的包: sun.misc.BASE64Decoder; sun.misc.BASE64Encoder;

返回结果:

aGVsbG8gd29ybGQ=
hello world

@org.junit.Test
    public void testBase64(){
        String string = "hello world";
        String encode =new BASE64Encoder().encode(string.getBytes());
        System.out.println(encode);
        try {
            byte[] result = new BASE64Decoder().decodeBuffer(encode);
            System.out.println( new String(result));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

数字签名

使用的包: sun.misc.BASE64Decoder; sun.misc.BASE64Encoder;

返回结果:

私钥:[B@2cfb4a64
公钥:[B@5474c6c
signature = X5gkjGn/ULpEftsLnLmqR7w1jPDtN7dH7GTl+Meh89zDyuYM2PVXhvLEyqwc1i+xiLUsv1WLy/q1
Jheiv3t2DcZIAyRyHHTqaQVDpSB5qWsDrkD6P+C3B8TKONiNuXqjOuUyQhQgj9EGLsZaMR1e6/aU
0EQqKB61fh2wwwFMqRyP/CqIKjjyf302CSrr9+ooHLI7JxzR6PVCK0TfDB1uQIkHFAzL+/XJWR1T
v0NZMC/QKdPqP+Qm34PRB6IIqUHXo23FPDhdMyLRaS//ZsA80hKE8WEMssIKELhICxCDVjxY2TuO
qftYYLhIqoz9yF18MzwLGiDjj7OEoQZ7paOmTg==
verify = true

@org.junit.Test
    public void verySingn() {
        String string = "hello world";
        try {
            /****************生成密钥部分*****************/
            KeyPair generator = KeyPairGenerator.getInstance("RSA").generateKeyPair();
            RSAPrivateKey privateKey = (RSAPrivateKey) generator.getPrivate();
            RSAPublicKey publicKey = (RSAPublicKey) generator.getPublic();

            String privateKeyStr = String.valueOf(Base64.encode(privateKey.getEncoded()));
            String publicKeyStr = String.valueOf(Base64.encode(publicKey.getEncoded()));

            System.out.println("私钥:" + privateKeyStr);
            System.out.println("公钥:" + publicKeyStr);

            /****************得到签名 && 验证签名部门*****************/
            // 获取签名对象
            Signature signature = Signature.getInstance("sha256withrsa");
            // 初始化签名
            signature.initSign(privateKey);
            // 传入原文
            signature.update(string.getBytes());
            // 签名
            byte[] sign = signature.sign();
            // Base64编码
            String encode = new BASE64Encoder().encode(sign);
            System.out.println("signature = " + encode);

            // 初始化校验
            signature.initVerify(publicKey);
            // 传入原文
            signature.update(string.getBytes());
            // 校验
            byte[] decode = new BASE64Decoder().decodeBuffer(encode);
            boolean verify = signature.verify(decode);

            System.out.println("verify = " + verify);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }

    }

摘要算法

package com.test.digest;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 消息摘要算法,为了防止篡改
 */
public class DigestDemo {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        // 原文
        String input = "Hello World";
        //  算法
        String algorithm = "MD5";
        String MD5 = getDigest(input, algorithm);
        // 使用base64进行转码
//        String encode = Base64.encode(digest1);
//        System.out.println("encode = " + encode);
        System.out.println("MD5 = " + MD5);
        System.out.println("MD5.length() = " + MD5.length());

        String sha1 = getDigest(input, "SHA-1");
        System.out.println("sha1 = " + sha1);
        System.out.println("sha1.length() = " + sha1.length());

        String sha256 = getDigest(input, "SHA-256");
        System.out.println("sha256 = " + sha256);
        System.out.println("sha256.length() = " + sha256.length());

        String sha512 = getDigest(input, "SHA-512");
        System.out.println("sha512 = " + sha512);
        System.out.println("sha512.length() = " + sha512.length());
    }

    private static String getDigest(String input, String algorithm) throws NoSuchAlgorithmException {
        // 创建消息摘要对象
        MessageDigest digest = MessageDigest.getInstance(algorithm);
        // 执行消息摘要算法
        byte[] digest1 = digest.digest(input.getBytes());
        System.out.println("密文的字节长度:" + digest1.length);
        // 转16进制
        return toHex(digest1);
    }

    private static String toHex(byte[] input) {
        StringBuilder sb = new StringBuilder();
        for (byte b : input) {
            // 转成 16进制
            String s = Integer.toHexString(b & 0xff);
            //System.out.println(s);
            if (s.length() == 1){
                // 如果生成的字符只有一个,前面补0
                s = "0"+s;
            }
            sb.append(s);
        }
        System.out.println(sb.toString());
        return sb.toString();
    }
}

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
DPhgMOoXTXDH