{"content":{"title":"密码学基础一对称加密和非对称加密","body":"# 对称加密\r\n既然说是对称加密就是在加密和解密的过程中，使用相同的秘钥。\r\n## DES 算法深入\r\n在DES算法中，密钥固定长度为64位。明文按64位进行分组，分组后的明文组和密钥按位置换或交换的方法形成密文组，然后再把密文组拼装成密文。\r\n密钥的每个第八位设置为奇偶校验位，也就是第8、16、24、32、40、48、56、64位，所以密钥的实际参与加密的长度为56位。\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2024/09/t6m9kIdE66e2f2cbe8124.png)\r\n\r\n它的核心步骤分为\r\n一  IP 初始置换  在第一轮运算之前执行，对输入的分组采用指定的数字进行 IP 初始变换\r\n二 子秘钥获取流程\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2024/09/l9u1tSVg66e2f2edf00c0.png)\r\n\r\n```js\r\n此处，用户输入 64 位的密钥。根据密钥置换表 PC-1，将 64 位变成 56 位密钥（此处去掉了奇偶校验位）。 \r\n\r\nPC-1 置换得到的 56 位密钥。此处密钥被分为前 28位 C0 和后 28 位 D0。分别对它们进行循环左移，C0 左移得到 C1，D0 左移得到 D1。 \r\n\r\n将 C1 和 D1 合并变成 56 位。然后通过 PC-2 表进行压缩置换，得到此轮的 48 位子密钥 K1。 \r\n\r\n再对 C1 和 D1 进行相同的左移和压缩置换，获取下一轮的子密钥……一共进行 16 轮，于是可以得到 16 个 48 bits 的子密钥。\r\n```\r\n三 S 盒扩展\r\n当产生了 48bits 密钥后就可以和明文进行异或运算，便可得到 48bits 的密文。再开始下轮的 S 盒迭代运算，其功能是把 6bit数据变为 4bits 数据，每个 S 盒是一个 4 行、16 列的表。每个 S盒的使用方法为：S 盒收到 6bits 的输入，6bits 的第 1 个 bit 和最后 1 个 bits 构成的 2 位二进制为该 S 盒行号，中间的 4bits 二进制为该 S 盒的列号，然后根据行号和列号查 S 盒定义表得到对应的值（通常为十进制），该值就是 S 盒变换的输出，并转化为二进制。\r\n四 E 盒扩展\r\n先将右半部分 32bits 按照 8 行 4 列方式依次排列，得到一个 8*4 的二维矩阵，经过E 盒扩展置换表扩展为 8*6 的二维矩阵。\r\n五 P 盒置换\r\nS 盒代替运算之后，输出 32bits，作为 F 函数最后一个变换 P 盒置换的输入。将该 32bits 位数据进行 P 盒置换，置换后得到一个仍然是 32 bits 的结果，此处可得 F 函数的输出值。\r\n六 逆初始置换 \r\nDES 完成 16 轮变换后，得到 64bits 数据作为 IP-1 逆初始置换的输入，64bits 输入数据位置重新编排，就得到 64bits 的密文。\r\n\r\n## DES实现案例\r\n\r\n```js\r\npublic class DES {\r\n\r\n    public static void main(String[] args) throws Exception {\r\n        // 原文:\r\n        String message = \"Hello, world!\";\r\n        System.out.println(\"Message: \" + message);\r\n        // 64位密钥 = 8 bytes Key:\r\n        // 只要保证秘钥长度为6，8位即可\r\n        byte[] key = \"12345678\".getBytes(\"UTF-8\");\r\n        // 加密:\r\n        byte[] data = message.getBytes(\"UTF-8\");\r\n        byte[] encrypted = encrypt(key, data);\r\n        System.out.println(\"Encrypted: \" + Base64.getEncoder().encodeToString(encrypted));\r\n        // 解密:\r\n        byte[] decrypted = decrypt(key, encrypted);\r\n        System.out.println(\"Decrypted: \" + new String(decrypted, \"UTF-8\"));\r\n    }\r\n\r\n    // 加密：\r\n    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {\r\n        Cipher cipher = Cipher.getInstance(\"DES\");\r\n        SecretKey keySpec = new SecretKeySpec(key, \"DES\");\r\n        cipher.init(Cipher.ENCRYPT_MODE, keySpec);\r\n        return cipher.doFinal(input);\r\n    }\r\n\r\n    // 解密:\r\n    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {\r\n        Cipher cipher = Cipher.getInstance(\"DES\");\r\n        SecretKey keySpec = new SecretKeySpec(key, \"DES\");\r\n        cipher.init(Cipher.DECRYPT_MODE, keySpec);\r\n        return cipher.doFinal(input);\r\n    }\r\n    \r\n}\r\n```\r\n\r\n# AES 算法深入\r\n## AES 算法深入\r\nAES算法的密钥长度是固定，密钥的长度可以使用128位、192位或256位。\r\nAES算法也是一种分组加密算法，其分组长度只能是128位。分组后的明文组和密钥使用几种不同的方法来执行排列和置换运算形成密文组，然后再把密文组拼装成密文。根据密匙 长 度的不同，加密的轮数也不同，本文采用长度为 128 位的密匙，加密轮数为 10 轮。AES 加密算法不仅编码紧凑、设计简单而且可抵抗多种类型的攻击，其基本结构包括 ４个部分。\r\n\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2024/09/YcKv44jx66e2f442eb383.png)\r\n基本结构\r\n第一步: 字节替换\r\n字节替换也就是通 过 S-BOX 对字节元素进行非线性的变换，S-BOX 由有限域 GF(2 的 8 次方) 上的乘法求逆运算和仿射变换运算而来，通过查表的方式即可直接得到变换前后的字节元素，替换后字节元素至少有两位发生变换，能 充分打乱原来的字节元素\r\n第二步: 行位移\r\n行位移是 AES 加密算法中的一个简单线性运算，即在 4 x 4 的状态矩阵中，把第ｉ行循环左移ｉ个字节(i＝0, 1, 2, 3)。\r\n第三步: 列混合\r\n列混合是将状态矩阵中的每一列看成一个多项式，让其与一个固定的多项式 a(x) 相乘，再做模多项式 m(x) = x4（x的四次方） + 1 的运算，其中 a(x)＝’03‘x3（x的3次方）+ ’01‘x2（x的平方）+ '01'x + ‘02’。\r\n第四步: 轮密匙加\r\n轮密匙加变换就是让状态矩阵与经过密匙扩展得到的子密匙做异或运算，因此轮密匙加变换的逆变换就是其本身，其中子密匙是原始密匙通过密匙扩展算法得到的。\r\n\r\n## AES实现案例\r\n\r\n```js\r\npublic class AES {\r\n\r\n    public static void main(String[] args) throws Exception {\r\n        // 原文:\r\n        String message = \"Hello, world!\";\r\n        System.out.println(\"Message: \" + message);\r\n        // 128位密钥 = 16 bytes Key:\r\n        // 只要保证秘钥长度为16，24，32位即可\r\n        byte[] key = \"0123456789abcdef\".getBytes(\"UTF-8\");\r\n        // 加密:\r\n        byte[] data = message.getBytes(\"UTF-8\");\r\n        byte[] encrypted = encrypt(key, data);\r\n        System.out.println(\"Encrypted: \" + Base64.getEncoder().encodeToString(encrypted));\r\n        // 解密:\r\n        byte[] decrypted = decrypt(key, encrypted);\r\n        System.out.println(\"Decrypted: \" + new String(decrypted, \"UTF-8\"));\r\n    }\r\n\r\n    // 加密：\r\n    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {\r\n        Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS5Padding\");\r\n        SecretKey keySpec = new SecretKeySpec(key, \"AES\");\r\n        cipher.init(Cipher.ENCRYPT_MODE, keySpec);\r\n        return cipher.doFinal(input);\r\n    }\r\n\r\n    // 解密:\r\n    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {\r\n        Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS5Padding\");\r\n        SecretKey keySpec = new SecretKeySpec(key, \"AES\");\r\n        cipher.init(Cipher.DECRYPT_MODE, keySpec);\r\n        return cipher.doFinal(input);\r\n    }\r\n}\r\n```\r\n\r\n# 非对称加密\r\n## RSA 算法深入\r\nRSA 算法是一种迄今为止理论上比较成熟和完善的公钥密码体制，是非对称密码体制的典型代表。\r\nRSA 算法由密钥的产生、加密算法和解密算法 3 个部分组成。\r\n密钥的产生过程如下：\r\n1. 产生两个大素数 p 和 q ；\r\n2. 计算 n=p×q，欧拉函数 φ(n)=(p−1)(q−1)\r\n3. 选择整数 e ，使其满足条件：1 < e < φ(n) ，且gcd(e,φ(n)) = 1（注：gcd () 函数计算两个数的最大公约数）；\r\n4. 计算 e 的逆元 d ：d∙e ≡ 1 mod φ(n)（注：由于gcd(e,φ(n)) = 1，则 d 一定存在）；\r\n5. 取序对 (e,n) 为公钥，可公开；(d,n) 为私钥，对外保密。\r\n\r\n加密算法过程如下：\r\n将要发送的字符串分割为长度为 m < n 的分组，然后对分组 m 执行加密运算，得到密文 c ：$c ≡(m)^e mod n$\r\n\r\n解密算法过程如下：\r\n收到密文 c 后，接收者使用自己的私钥执行解密运算，得到明文 m ：$m ≡(c)^d mod n$\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2024/09/KEWYavnH66e2f540eb9c7.png)\r\n\r\n## RSA算法实现\r\n\r\n```js\r\npublic static void main(String[] args) {\r\n    // 生成 RSA 密钥对\r\n    KeyPair keyPair = generateKeyPair();\r\n    PublicKey publicKey = keyPair.getPublic();\r\n    PrivateKey privateKey = keyPair.getPrivate();\r\n\r\n    // 要加密的明文\r\n    String plainText = \"Hello, this is a test message!\";\r\n\r\n    // 加密\r\n    String encryptedText = encrypt(plainText, publicKey);\r\n    System.out.println(\"Encrypted Text: \" + encryptedText);\r\n\r\n    // 解密\r\n    String decryptedText = decrypt(encryptedText, privateKey);\r\n    System.out.println(\"Decrypted Text: \" + decryptedText);\r\n}\r\n\r\n// 生成密钥对\r\npublic static KeyPair generateKeyPair() throws NoSuchAlgorithmException {\r\n    KeyPairGenerator keyGen = KeyPairGenerator.getInstance(\"RSA\");\r\n    keyGen.initialize(2048); // 密钥大小 2048 位\r\n    return keyGen.generateKeyPair();\r\n}\r\n\r\n// 加密\r\npublic static String encrypt(String plainText, PublicKey publicKey) throws Exception {\r\n    Cipher cipher = Cipher.getInstance(\"RSA\");\r\n    cipher.init(Cipher.ENCRYPT_MODE, publicKey);\r\n    byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());\r\n    return Base64.getEncoder().encodeToString(encryptedBytes); // 将加密后的字节转为 Base64 字符串\r\n}\r\n\r\n// 解密\r\npublic static String decrypt(String cipherText, PrivateKey privateKey) throws Exception {\r\n    Cipher cipher = Cipher.getInstance(\"RSA\");\r\n    cipher.init(Cipher.DECRYPT_MODE, privateKey);\r\n    byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));\r\n    return new String(decryptedBytes); // 将解密后的字节转为原始字符串\r\n}\r\n```\r\n\r\n## 其他依赖于非对称加密的技术\r\nECDSA 和 EDDSA 都不是椭圆加密算法，它们都使用非对称密钥对（公钥和私钥），但它的主要作用是进行 签名和验证，而不是加密。\r\n至于GPG算法，虽然它也使用了非对称加密技术，但是它实际加密数据还是用的是对称加密算法来实现的，GPG 使用非对称加密算法（如 RSA 或 ECC）来加密消息的对称密钥，或者直接加密小数据块。"},"author":{"user":"https://learnblockchain.cn/people/22539","address":null},"history":"bafkreicczrykgumtzphuk3qwxpyloqlnjjmkzhfw7khourlzbemuepr23q","timestamp":1726150665,"version":1}