文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

我们一起聊聊加解密的艺术

2024-11-29 19:38

关注

一 对称加密

对称加密和非对称加密是两种不同的加密方法,它们在数据安全和信息传输中扮演着重要的角色。下面我将分别介绍这两种加密技术:

1.1 对称加密(Symmetric Encryption)

对称加密是指加密和解密都使用相同的密钥。这意味着发送方和接收方都必须拥有这个密钥才能进行加密和解密操作。

常见的对称加密算法:

1.2 对称加密特点

一般来说,对称加密具有如下特点:

从这里可以看到,对称加密主要有两大优势:第一就是运算速度快;第二就是适用于大量数据。

但是,对称加密有一个致命的问题,就是密钥管理。如何从服务端将密钥安全的传输到客户端是个问题!另外就是当一对多通信的时候,如何管理好密钥不被泄露也是一个考验。这是对称加密的不足之处。

1.3 代码案例

接下来松哥给大家演示下 Java 代码如何做对称加解密。

在 Java 中实现对称加密,通常使用 Java 加密架构(Java Cryptography Architecture, JCA)提供的类和接口。

下面是一个使用 AES(高级加密标准)算法进行对称加密和解密的简单示例:

public class SymmetricEncryptionExample {

    // 生成密钥
    public static SecretKey generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128); // 可以是128, 192或256位
        return keyGenerator.generateKey();
    }

    // 加密方法
    public static String encrypt(String data, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    // 解密方法
    public static String decrypt(String encryptedData, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(decryptedBytes);
    }

    public static void main(String[] args) {
        try {
            // 生成密钥
            SecretKey key = generateKey();

            // 原始数据
            String originalData = "Hello, JavaBoy!";

            // 加密
            String encryptedData = encrypt(originalData, key);
            System.out.println("加密数据: " + encryptedData);

            // 解密
            String decryptedData = decrypt(encryptedData, key);
            System.out.println("解密数据: " + decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上代码大家需要注意的是:

出于安全考虑,我们一般使用上面的方案生成密钥。这种方案生成的密钥有一个特点就是系统每次重启就会变。如果你希望能够自己控制密钥的生成,那么可以通过如下方式生成密钥:

public static SecretKey generateKeyFromPassword(String password, int keySize) throws NoSuchAlgorithmException, InvalidKeySpecException {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    KeySpec spec = new PBEKeySpec(password.toCharArray(), "salt".getBytes(), 65536, keySize);
    return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
}

这样就可以通过自己传入的参数去控制密钥。

1.4 前后端搭配

在跨语言(如 JavaScript 和 Java)使用 AES 算法进行加密和解密时,关键是确保两端使用相同的密钥、算法模式(如 CBC, ECB 等)、填充模式(如 PKCS5Padding, PKCS7Padding 等)和初始化向量(IV,如果使用了需要 IV的 模式如 CBC)。

之前有小伙伴说自己前端加密之后后端总是无法解密,松哥这里也给一个前后端搭配的例子。

前端加密后端解密

前端代码:




    
    AES加密示例
    





后端代码:

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

public class AESDecrypt {

    public static String decryptAES(String encryptedData, String secretKey, String iv) throws Exception {
        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

        byte[] decodedValue = Base64.getDecoder().decode(encryptedData);
        byte[] decryptedValue = cipher.doFinal(decodedValue);

        return new String(decryptedValue, "UTF-8");
    }

    public static void main(String[] args) {
        try {
            //前端加密后的文本
            String encryptedText = "PYANpAjMsRnBIEhovtEXQw==";
            String secretKey = "helloworldhelloworldhelloworld11";
            //前端 IV,要和加密后的文本一起传到后端
            String iv = "y/jUHcgSOpOiyNlsfjNUBg==";

            String decryptedText = decryptAES(encryptedText, secretKey, iv);
            System.out.println("解密文本: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意这里前端加密时会产生一个 iv 参数,要随着前端加密结果一起传递给后端。

后端加密前端解密

在 Java 进行 AES 加密并在 JavaScript 中解密时,同样需要确保两端使用相同的密钥、算法模式(如 CBC、ECB 等)、填充模式(如 PKCS5Padding、PKCS7Padding 等)以及(如果适用)相同的初始化向量(IV)。

后端代码:

public class AESEncrypt {

    public static String encryptAES(String plainText, String secretKey, String iv) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256); // 对于AES-256
        SecretKey secret = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");

        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret, ivParameterSpec);

        byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static void main(String[] args) {
        try {
            String plainText = "Hello, 江南一点雨!";
            String secretKey = "helloworldhelloworldhelloworld11"; // 确保密钥是32个字符长(256位)
            String iv = Base64.getEncoder().encodeToString(new byte[16]); // 示例IV,实际应用中应更安全地生成

            String encryptedText = encryptAES(plainText, secretKey, iv);
            System.out.println("Encrypted text: " + encryptedText);
            System.out.println("IV (Base64): " + iv); // 确保将IV发送给解密方

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

前端代码:




    
    Title
    
    




以上前后端交互加解密代码松哥亲测都是没问题的,大家有这方面的需求记得及时收藏本文,可以作为参考。

二 非对称加密

2.1 什么是非对称加密

非对称加密,也称为公钥加密,是一种使用两个不同密钥(公钥和私钥)的加密方式。

一般来说,非对称加密有如下几种不同的特点:

  1. 公钥与私钥

公钥与私钥的生成:非对称加密使用一对密钥,公钥是公开的,任何人都可以访问,而私钥是私有的,只有密钥的持有者可以访问。这两个密钥是由数学算法生成的,且相互关联但不可从一方推导出另一方。

  1. 安全性高

难以破解:由于公钥和私钥的复杂数学关系,非对称加密的安全性较高。攻击者很难从公钥中推断出私钥,从而保证了加密数据的安全性。

抗量子计算攻击:一些区块链项目开始采用抗量子计算攻击的加密算法,如椭圆曲线数字签名算法(ECDSA)的量子安全变体,以应对未来量子计算的威胁。

  1. 公开密钥分发方便

公钥的公开性:公钥可以公开给任何人,因此分发起来非常方便。任何人都可以使用公钥来加密数据,但只有私钥持有者才能解密。

  1. 身份验证与数字签名

身份验证:公钥可以用作用户的身份标识,其他人可以验证用户的身份而无需了解其私钥。这有助于在区块链等去中心化网络中建立可信身份。

数字签名:私钥持有者可以使用私钥对消息进行签名,其他人则可以使用公钥来验证签名的真实性。这确保了消息的完整性和来源的可靠性。

  1. 安全通信

加密通信:公钥可以用于加密消息,只有持有相应私钥的人才能解密。这确保了通信过程中的数据安全,防止了信息被未经授权的人员访问。

  1. 数字资产控制

区块链地址与私钥:区块链地址通常由公钥派生而来,用户通过私钥来控制与该地址相关联的数字资产。私钥的安全性对数字资产的安全至关重要。

  1. 加密解密速度

相对较慢:非对称加密的加密和解密速度相对于对称加密要慢得多,因为它需要进行更加复杂的数学计算。然而,这并不影响其在安全通信、身份验证等领域的应用。

2.2 非对称加密的用途

非对称加密有两个经典使用场景。

针对第二点用途,有的小伙伴会将之表述为用私钥进行加密,公钥进行解密,反正大伙知道说的是同一回事。

非对称加密算法,尽管在理论上能够用于数据加密和数字签名,但在实践中,其高计算复杂度和低效率成为了主要障碍。

相比对称加密算法,非对称加密的运算速度要慢上几个数量级,这极大地影响了其处理大数据量的能力。此外,由于非对称加密算法的加密和解密过程与密钥长度紧密相关,且不支持分组加密模式,导致它只能处理不超过密钥长度的少量数据,无法进行大量数据的加密。

为了克服非对称加密在性能上的不足,现代加密系统通常采用混合加密策略,即结合对称加密和非对称加密的优点。在这种策略中,非对称加密主要用于安全地传输一个对称加密的密钥(即“密钥协商”)给另一方。一旦双方安全地共享了这个对称密钥,就可以使用高效的对称加密算法来加密和解密大量数据。这种结合使用的方法不仅提高了加密效率,还增强了通信的安全性,被广泛应用于各种安全通信协议中,如SSL/TLS。

在数字签名领域,为了提升非对称加密的效率也做了一些适配。具体做法是,首先对原始数据进行摘要处理(可以利用 MD5、SHA 等),得到一个固定长度的摘要值。然后,使用非对称加密算法对这个摘要值进行加密,生成数字签名。由于摘要算法能够高效地将任意长度的数据压缩为固定长度的摘要,因此不管原始数据多大,摘要数据长度都一样,签名过程也能保持高效。当验证签名时,只需重新计算原始数据的摘要,并与解密后的签名进行比较,即可快速判断数据是否被篡改。

2.3 加密案例

Java 代码使用 RSA 加解密案例:

public class RsaDemo {
    public static void main(String[] args) {
        try {
            KeyPair keyPair = generateRSAKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            String originalData = "Hello, 江南一点雨!";
            String encryptedData = encrypt(publicKey, originalData);
            String decryptedData = decrypt(privateKey, encryptedData);

            System.out.println("加密后的数据: " + encryptedData);
            System.out.println("解密后的数据: " + decryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String decrypt(PrivateKey privateKey, String encryptedData) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(decryptedBytes);
    }

    public static String encrypt(PublicKey publicKey, String data) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bytes = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(bytes);
    }

    public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048); // 可以指定密钥长度,如2048位
        return keyGen.generateKeyPair();
    }
}

2.4 前后端搭配

前端加密后端解密

后端代码和上面案例中一致,不同的是,我们在拿到公钥之后,可以将公钥打印出来,这个公钥将来要传递给前端:

public static void main(String[] args) {
    try {
        KeyPair keyPair = generateRSAKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println("公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        String originalData = "Hello, 江南一点雨!";
        String encryptedData = encrypt(publicKey, originalData);
        String decryptedData = decrypt(privateKey, encryptedData);
        System.out.println("加密后的数据: " + encryptedData);
        System.out.println("解密后的数据: " + decryptedData);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

前端代码如下:




    
    
    RSA Encryption Example
    
    




后端加密前端解密

在 Java 中使用 RSA 算法加密数据,并在 JavaScript 中解密这些数据,意味着服务端用前端的公钥加密,前端用自己的私钥解密,这种场景前端私钥很容易被盗取,因此不推荐这种用法。我也就不举例了。

好啦,又和小伙伴们聊了一遍对称加密和非对称加密,上面的案例代码松哥都是测试通过的,小伙伴们可以作为参考。

来源:江南一点雨内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯