密码学基础一对称加密和非对称加密

  • Leo
  • 更新于 2024-09-12 22:17
  • 阅读 811

对称加密既然说是对称加密,那么加密和解密的时候,使用相同的秘钥。DES算法深入在DES算法中,密钥固定长度为64位。明文按64位进行分组,分组后的明文组和密钥按位置换或交换的方法形成密文组,然后再把密文组拼装成密文。密钥的每个第八位设置为奇偶校验位,也就是第8、16、24、32、40、48

对称加密

既然说是对称加密就是在加密和解密的过程中,使用相同的秘钥。

DES 算法深入

在DES算法中,密钥固定长度为64位。明文按64位进行分组,分组后的明文组和密钥按位置换或交换的方法形成密文组,然后再把密文组拼装成密文。 密钥的每个第八位设置为奇偶校验位,也就是第8、16、24、32、40、48、56、64位,所以密钥的实际参与加密的长度为56位。

image.png

它的核心步骤分为 一 IP 初始置换 在第一轮运算之前执行,对输入的分组采用指定的数字进行 IP 初始变换 二 子秘钥获取流程

image.png

此处,用户输入 64 位的密钥。根据密钥置换表 PC-1,将 64 位变成 56 位密钥(此处去掉了奇偶校验位)。 

PC-1 置换得到的 56 位密钥。此处密钥被分为前 28位 C0 和后 28 位 D0。分别对它们进行循环左移,C0 左移得到 C1,D0 左移得到 D1。 

将 C1 和 D1 合并变成 56 位。然后通过 PC-2 表进行压缩置换,得到此轮的 48 位子密钥 K1。 

再对 C1 和 D1 进行相同的左移和压缩置换,获取下一轮的子密钥……一共进行 16 轮,于是可以得到 16 个 48 bits 的子密钥。

三 S 盒扩展 当产生了 48bits 密钥后就可以和明文进行异或运算,便可得到 48bits 的密文。再开始下轮的 S 盒迭代运算,其功能是把 6bit数据变为 4bits 数据,每个 S 盒是一个 4 行、16 列的表。每个 S盒的使用方法为:S 盒收到 6bits 的输入,6bits 的第 1 个 bit 和最后 1 个 bits 构成的 2 位二进制为该 S 盒行号,中间的 4bits 二进制为该 S 盒的列号,然后根据行号和列号查 S 盒定义表得到对应的值(通常为十进制),该值就是 S 盒变换的输出,并转化为二进制。 四 E 盒扩展 先将右半部分 32bits 按照 8 行 4 列方式依次排列,得到一个 84 的二维矩阵,经过E 盒扩展置换表扩展为 86 的二维矩阵。 五 P 盒置换 S 盒代替运算之后,输出 32bits,作为 F 函数最后一个变换 P 盒置换的输入。将该 32bits 位数据进行 P 盒置换,置换后得到一个仍然是 32 bits 的结果,此处可得 F 函数的输出值。 六 逆初始置换 DES 完成 16 轮变换后,得到 64bits 数据作为 IP-1 逆初始置换的输入,64bits 输入数据位置重新编排,就得到 64bits 的密文。

DES实现案例

public class DES {

    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message: " + message);
        // 64位密钥 = 8 bytes Key:
        // 只要保证秘钥长度为6,8位即可
        byte[] key = "12345678".getBytes("UTF-8");
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("DES");
        SecretKey keySpec = new SecretKeySpec(key, "DES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(input);
    }

    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("DES");
        SecretKey keySpec = new SecretKeySpec(key, "DES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(input);
    }

}

AES 算法深入

AES 算法深入

AES算法的密钥长度是固定,密钥的长度可以使用128位、192位或256位。 AES算法也是一种分组加密算法,其分组长度只能是128位。分组后的明文组和密钥使用几种不同的方法来执行排列和置换运算形成密文组,然后再把密文组拼装成密文。根据密匙 长 度的不同,加密的轮数也不同,本文采用长度为 128 位的密匙,加密轮数为 10 轮。AES 加密算法不仅编码紧凑、设计简单而且可抵抗多种类型的攻击,其基本结构包括 4个部分。

image.png 基本结构 第一步: 字节替换 字节替换也就是通 过 S-BOX 对字节元素进行非线性的变换,S-BOX 由有限域 GF(2 的 8 次方) 上的乘法求逆运算和仿射变换运算而来,通过查表的方式即可直接得到变换前后的字节元素,替换后字节元素至少有两位发生变换,能 充分打乱原来的字节元素 第二步: 行位移 行位移是 AES 加密算法中的一个简单线性运算,即在 4 x 4 的状态矩阵中,把第i行循环左移i个字节(i=0, 1, 2, 3)。 第三步: 列混合 列混合是将状态矩阵中的每一列看成一个多项式,让其与一个固定的多项式 a(x) 相乘,再做模多项式 m(x) = x4(x的四次方) + 1 的运算,其中 a(x)=’03‘x3(x的3次方)+ ’01‘x2(x的平方)+ '01'x + ‘02’。 第四步: 轮密匙加 轮密匙加变换就是让状态矩阵与经过密匙扩展得到的子密匙做异或运算,因此轮密匙加变换的逆变换就是其本身,其中子密匙是原始密匙通过密匙扩展算法得到的。

AES实现案例

public class AES {

    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message: " + message);
        // 128位密钥 = 16 bytes Key:
        // 只要保证秘钥长度为16,24,32位即可
        byte[] key = "0123456789abcdef".getBytes("UTF-8");
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(input);
    }

    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(input);
    }
}

非对称加密

RSA 算法深入

RSA 算法是一种迄今为止理论上比较成熟和完善的公钥密码体制,是非对称密码体制的典型代表。 RSA 算法由密钥的产生、加密算法和解密算法 3 个部分组成。 密钥的产生过程如下:

  1. 产生两个大素数 p 和 q ;
  2. 计算 n=p×q,欧拉函数 φ(n)=(p−1)(q−1)
  3. 选择整数 e ,使其满足条件:1 < e < φ(n) ,且gcd(e,φ(n)) = 1(注:gcd () 函数计算两个数的最大公约数);
  4. 计算 e 的逆元 d :d∙e ≡ 1 mod φ(n)(注:由于gcd(e,φ(n)) = 1,则 d 一定存在);
  5. 取序对 (e,n) 为公钥,可公开;(d,n) 为私钥,对外保密。

加密算法过程如下: 将要发送的字符串分割为长度为 m < n 的分组,然后对分组 m 执行加密运算,得到密文 c :$c ≡(m)^e mod n$

解密算法过程如下: 收到密文 c 后,接收者使用自己的私钥执行解密运算,得到明文 m :$m ≡(c)^d mod n$

image.png

RSA算法实现

public static void main(String[] args) {
    // 生成 RSA 密钥对
    KeyPair keyPair = generateKeyPair();
    PublicKey publicKey = keyPair.getPublic();
    PrivateKey privateKey = keyPair.getPrivate();

    // 要加密的明文
    String plainText = "Hello, this is a test message!";

    // 加密
    String encryptedText = encrypt(plainText, publicKey);
    System.out.println("Encrypted Text: " + encryptedText);

    // 解密
    String decryptedText = decrypt(encryptedText, privateKey);
    System.out.println("Decrypted Text: " + decryptedText);
}

// 生成密钥对
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(2048); // 密钥大小 2048 位
    return keyGen.generateKeyPair();
}

// 加密
public static String encrypt(String plainText, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
    return Base64.getEncoder().encodeToString(encryptedBytes); // 将加密后的字节转为 Base64 字符串
}

// 解密
public static String decrypt(String cipherText, PrivateKey privateKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
    return new String(decryptedBytes); // 将解密后的字节转为原始字符串
}

其他依赖于非对称加密的技术

ECDSA 和 EDDSA 都不是椭圆加密算法,它们都使用非对称密钥对(公钥和私钥),但它的主要作用是进行 签名和验证,而不是加密。 至于GPG算法,虽然它也使用了非对称加密技术,但是它实际加密数据还是用的是对称加密算法来实现的,GPG 使用非对称加密算法(如 RSA 或 ECC)来加密消息的对称密钥,或者直接加密小数据块。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Leo
Leo
江湖只有他的大名,没有他的介绍。