加密(二)对称加密

目录

一、介绍

1、概念

2、示例

3、特点

4、常见算法

(1)DES

(2)AES

二、 DES 加密解密

1、加密

1.1、使用方法

1.2、demo

2、解密

三、 AES 加密解密


一、介绍

1、概念

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。

2、示例

现在一个原文3要发送给B;

设置密钥为108, 3 * 108 = 324, 将324作为密文发送给B;

B拿到密文324后, 使用324/108 = 3 得到原文。

3、特点
  • 加密速度快, 可以加密大文件
  • 密文可逆, 一旦密钥文件泄漏, 就会导致数据暴露
  • 加密后编码表找不到对应字符, 出现乱码
  • 一般结合Base64使用
4、常见算法
(1)DES

Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。

Cipher 的相关文档: https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html#getInstance-java.lang.String-

(2)AES

Advanced Encryption Standard, 高级加密标准 .在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。

AES是一种高效且安全的对称加密算法,支持128位、192位和256位密钥长度,用于加密敏感数据。

二、 DES 加密解密

1、实现方法

1) 密钥key必须是8个字节;

2) 密文需要结合base64使用,加密后将密文encode,解密前也需要decode;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class DesUtil {
    // DES加密算法,key的大小必须是8个字节

    public static void main(String[] args) throws Exception {
        String input ="测试wtyy666";
        // DES加密算法,key的大小必须是8个字节
        String key = "12345678";

        String transformation = "DES"; // 9PQXVUIhaaQ=
        // 指定获取密钥的算法
        String algorithm = "DES";
        String encryptDES = encryptDES(input, key, transformation, algorithm);
        System.out.println("加密:" + encryptDES);
        String s = decryptDES(encryptDES, key, transformation, algorithm);
        System.out.println("解密:" + s);

    }

    /**
     * 使用DES加密数据
     *
     * @param input          : 原文
     * @param key            : 密钥(DES,密钥的长度必须是8个字节)
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @return : 密文
     * @throws Exception
     */
    private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 创建加密规则
        // 第一个参数key的字节
        // 第二个参数表示加密算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // ENCRYPT_MODE:加密模式
        // DECRYPT_MODE: 解密模式
        // 初始化加密模式和算法
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // 加密
        byte[] bytes = cipher.doFinal(input.getBytes());

        // 输出加密后的数据
        String encode = Base64.getEncoder().encodeToString(bytes);

        return encode;
    }

    /**
     * 使用DES解密
     *
     * @param input          : 密文
     * @param key            : 密钥
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @throws Exception
     * @return: 原文
     */
    private static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 1,获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定密钥规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 3. 解密,上面使用的base64编码,下面直接用密文
        byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(input));
        //  因为是明文,所以直接返回
        return new String(bytes);
    }
}

加密:YJGgjRe/Rp22cCH1YpRtlQ==
解密:测试wtyy666
2、测试
(1)密钥必须是8个字节
    public static void main(String[] args) throws Exception{
        // 原文
        String input = "测试wtyy666";
        // des加密必须是8位
        String key = "123456";
        // 算法
        String algorithm = "DES";
        String transformation = "DES";
        // Cipher:密码,获取加密对象
        // transformation:参数表示使用什么类型加密
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定秘钥规则
        // 第一个参数表示:密钥,key的字节数组
        // 第二个参数表示:算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // 对加密进行初始化
        // 第一个参数:表示模式,有加密模式和解密模式
        // 第二个参数:表示秘钥规则
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // 进行加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        // 打印密文
        System.out.println(new String(bytes));
    }
}

加密运行报错:

改为大于8个字节

String key = "1234567890";

 仍然报同样的错;

改为8个字节:

String key = "12345678";

(2)需要结合base64

上面运行虽然不报错,但是密文出现了乱码,这是因为对应的字节出现负数,但负数没有出现在 ascii 码表里面,所以出现乱码,需要配合base64进行转码:

 // 打印密文
        String encode = Base64.getEncoder().encodeToString(bytes);
        System.out.println(encode);

再次执行打印:

以上,解密也是同样的。

(3)加密解密需要使用同一个key

则解密报错

三、 AES 加密解密

1、实现方法

AES 加密解密和 DES 加密解密代码一样,只需要修改加密算法就行,拷贝 ESC 代码。

AES 的时候需要注意,key需要16个字节,加密向量也需要16个字节 ,其他方式跟 DES 一样。

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AesUtil {
    // DES加密算法,key的大小必须是8个字节

    public static void main(String[] args) throws Exception {
        String input ="测试wtyy666";
        // AES加密算法,比较高级,所以key的大小必须是16个字节
        String key = "1234567812345678";

        String transformation = "AES"; 
        // 指定获取密钥的算法
        String algorithm = "AES";
        // 先测试加密,然后在测试解密
        String encryptDES = encryptDES(input, key, transformation, algorithm);
        System.out.println("加密:" + encryptDES);
        String s = dncryptDES(encryptDES, key, transformation, algorithm);
        System.out.println("解密:" + s);
    }

    /**
     * 使用DES加密数据
     *
     * @param input          : 原文
     * @param key            : 密钥(DES,密钥的长度必须是8个字节)
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @return : 密文
     * @throws Exception
     */
    private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 创建加密规则
        // 第一个参数key的字节
        // 第二个参数表示加密算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // ENCRYPT_MODE:加密模式
        // DECRYPT_MODE: 解密模式
        // 初始化加密模式和算法
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // 加密
        byte[] bytes = cipher.doFinal(input.getBytes());

        // 输出加密后的数据
        String encode = Base64.getEncoder().encodeToString(bytes);
        return encode;
    }

    /**
     * 使用DES解密
     *
     * @param input          : 密文
     * @param key            : 密钥
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @throws Exception
     * @return: 原文
     */
    private static String dncryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 1,获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定密钥规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 3. 解密
        byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(input));

        return new String(bytes);
    }
}

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
...
private final static int GCM_NONCE_LENGTH = 12;
private final static int TLEN = 128;
...
public static String[] encryptMessage(String message, String nonce, String key) throws Exception {
    
    byte[] encodedNonce = Base64.getDecoder().decode(nonce);
    byte[] encodedKey = Base64.getDecoder().decode(key);
    
    SecretKey secretKey = new SecretKeySpec(encodedKey, "AES");
    byte[] encodedTag = "ProtocolVersion1".getBytes(StandardCharsets.UTF_8);
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec parameterSpec = new GCMParameterSpec(TLEN, encodedNonce);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
    if (encodedTag != null) {
        cipher.updateAAD(encodedTag);
    }
    byte[] ciphertext = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
    ByteBuffer byteBuffer = ByteBuffer.allocate(encodedNonce.length + ciphertext.length);
    byteBuffer.put(encodedNonce);
    byteBuffer.put(ciphertext);
    
    String decodedCiphertext = Base64.getEncoder().encodeToString(byteBuffer.array());
    String decodedTag = Base64.getEncoder().encodeToString(encodedTag);
    
    return new String[] {decodedCiphertext, decodedTag};
}



public static String decryptMessage(String ciphertext, String key, String tag) throws Exception{
 
    byte[] encodedCiphertext = Base64.getDecoder().decode(ciphertext);
    byte[] encodedKey = Base64.getDecoder().decode(key);
    byte[] encodedTag = Base64.getDecoder().decode(tag);
    SecretKey secretKey = new SecretKeySpec(encodedKey, "AES");
    
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    AlgorithmParameterSpec gcmIv = new GCMParameterSpec(TLEN, encodedCiphertext, 0, GCM_NONCE_LENGTH);
    cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
    if (encodedTag != null) {
        cipher.updateAAD(encodedTag);
    }
    byte[] encodedPlaintext = cipher.doFinal(encodedCiphertext, GCM_NONCE_LENGTH, encodedCiphertext.length - GCM_NONCE_LENGTH);

    String plaintext = new String(encodedPlaintext, StandardCharsets.UTF_8);
    return plaintext;
}
2、测试

(1)key必须为16个字节

否则报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值