对称式加密与非对称式加密的对比

对称加密算法简单来说,就是传统的用一个密码来进行加密和解密。而非对称式加密则是加密和解密使用的是不同的密钥;要用一个公钥-私钥对才能正常进行加密解密。

对称式加密算法:

        从程序的角度看,加密就是接收密码和明文,然后输出密文。 解密就是接收密码和密文,输出明文。

常用的对称加密算法有:

 由于DES已经不常用了,在这里我们以最广泛的AES加密算法的常见工作模式ECB和CBC为例,看一下对称加密的过程和程序代码。

ECB工作模式:(最简单的AES加密的工作模式)

1、准备原文和128位密钥的byte[] 数组。

2、然后进入正式的加密环节,创建密码对象Cipher,需要传入的参数数(算法,工作模式,填充模式)

3、根据key的字节内容,初始化一个SecretKey实例,恢复密钥对象(key,算法名称)

4、初始化密钥,使用SecretKey初始化cipher实例并设置加密或解密模式(加密/解密,SecretKey)

5、根据原始字节内容,进行加密/解密cipher. doFinal(明文/密文)

import java.security.*;
import java.util.Base64;

import javax.crypto.*;
import javax.crypto.spec.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message(原始信息): " + message);
        
        // 128位密钥 = 16 bytes Key:
        byte[] key = "1234567890abcdef".getBytes();
        
        // 调用加密方法:
        byte[] data = message.getBytes();
        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));
    }

    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
    	// 创建密码对象,需要传入算法/工作模式/填充模式
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    	
        // 根据key的字节内容,"恢复"秘钥对象
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        
        // 初始化秘钥:设置加密模式ENCRYPT_MODE
        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");
        
    	// 根据key的字节内容,"恢复"秘钥对象
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        
        // 初始化秘钥:设置解密模式DECRYPT_MODE
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        
        // 根据原始内容(字节),进行解密
        return cipher.doFinal(input);
    }
}

 CBC工作模式:

使用CBC需要一份随机数作为IV参数,对于同一份明文,每次生成的密文都不同。

    // 加密:
    //调用加密方法时时分别传入原文和密钥的byte[] 数组
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 设置算法/工作模式CBC/填充
    	Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    	
    	// 恢复秘钥对象
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        
        // CBC模式需要生成一个16 bytes的initialization vector:
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16); // 生成16个字节的随机数
        System.out.println(Arrays.toString(iv));//打印观察随机数组
        IvParameterSpec ivps = new IvParameterSpec(iv); // 随机数封装成IvParameterSpec参数对象
        
        // 初始化秘钥:操作模式、秘钥、IV参数
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
        
        // 加密
        byte[] data = cipher.doFinal(input);
        
        // IV不需要保密,把IV和密文一起返回:
        return join(iv, data);
    }


    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 把input分割成IV和密文:
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        
        System.arraycopy(input, 0, iv, 0, 16); // IV
        System.arraycopy(input, 16, data, 0, data.length); //密文
        System.out.println(Arrays.toString(iv));
        
        // 解密:
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 密码对象
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); // 恢复秘钥
        IvParameterSpec ivps = new IvParameterSpec(iv); // 恢复IV
        
        // 初始化秘钥:操作模式、秘钥、IV参数
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        
        // 解密操作
        return cipher.doFinal(data);
    }
    
    // 合并数组
    public static byte[] join(byte[] bs1, byte[] bs2) {
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }

使用对称加密算法需要指定算法名称、工作模式、填充模式。

 在对称加密算法过程中,除了密文,还需要传递密钥,顺带叙述以下密钥交换算法的实现过程,密钥交换,顾名思义,就是传输密钥:假设了两个人,Alice和Bob;Alice和Bob分别有一个私钥a和b,且都分别通过自己的私钥算出了公钥A和公钥B,再把自己的公钥发给对方,这样Alice就有了自己的私钥a和Bob的公钥B;Bob有了私钥b和Alice的公钥A;最后,他们分别根据自己持有的值 通过计算得出了共享密钥。他们的私钥都没有在网络上传输,但可以通过公钥传输计算,最后得到了相同的密钥。(配合如下图示理解密钥交换的过程)

 非对称加密算法:

        非对称加密算法,是使用公钥-私钥对来完成,即加密和解密使用不同的密钥。 大概意思是,假如你要给别人传文件,你需要先拿到对方的公钥,用对方的公钥加密,然后传给对方,那么这个文件就只能对方用自己的私钥才能打开。

import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;

// RSA
public class Main {
	public static void main(String[] args) throws Exception {
		// 明文:
		byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");

		// 创建公钥/私钥对:
		Human alice = new Human("Alice");

		// 用Alice的公钥加密:
		// 获取Alice的公钥,并输出
		byte[] pk = alice.getPublicKey();
		System.out.println(String.format("public key(公钥): %x", new BigInteger(1, pk)));

		// 使用公钥加密
		byte[] encrypted = alice.encrypt(plain);
		System.out.println(String.format("encrypted(加密): %x", new BigInteger(1, encrypted)));

		// 用Alice的私钥解密:
		// 获取Alice的私钥,并输出
		byte[] sk = alice.getPrivateKey();
		System.out.println(String.format("private key(私钥): %x", new BigInteger(1, sk)));

		// 使用私钥解密
		byte[] decrypted = alice.decrypt(encrypted);
		System.out.println("decrypted(解密): " + new String(decrypted, "UTF-8"));
	}
}

// 用户类
class Human {
	// 姓名
	String name;

	// 私钥:
	PrivateKey sk;

	// 公钥:
	PublicKey pk;

	// 构造方法
	public Human(String name) throws GeneralSecurityException {
		// 初始化姓名
		this.name = name;

		// 生成公钥/私钥对:
		KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
		kpGen.initialize(1024);
		KeyPair kp = kpGen.generateKeyPair();

		this.sk = kp.getPrivate();
		this.pk = kp.getPublic();
	}

	// 把私钥导出为字节
	public byte[] getPrivateKey() {
		return this.sk.getEncoded();
	}

	// 把公钥导出为字节
	public byte[] getPublicKey() {
		return this.pk.getEncoded();
	}

	// 用公钥加密:
	public byte[] encrypt(byte[] message) throws GeneralSecurityException {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, this.pk); // 使用公钥进行初始化
		return cipher.doFinal(message);
	}

	// 用私钥解密:
	public byte[] decrypt(byte[] input) throws GeneralSecurityException {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, this.sk); // 使用私钥进行初始化
		return cipher.doFinal(input);
	}
}

  • 20
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
RSA 是一种非对称加密算法,它可以用于数据加密和数字签名。下面是 RSA 加密算法的实现过程: 1. 选择两个大素数 p 和 q,并计算 n = p*q。 2. 计算欧拉函数 φ(n) = (p-1)*(q-1)。 3. 选择一个小于 φ(n) 的整数 e,使得 e 和 φ(n) 互质。 4. 计算 e 的模反元素 d,即满足 (d*e) mod φ(n) = 1 的整数 d。可以使用扩展欧几里得算法来计算 d。 5. 公钥为 (n, e),私钥为 (n, d)。 6. 加密时,将消息 m 转换成整数 M,然后计算密文 C = M^e mod n。 7. 解密时,将密文 C 计算出明文 M = C^d mod n。 下面是 Python 实现 RSA 加密算法的代码: ```python import random def gcd(a, b): if b == 0: return a else: return gcd(b, a % b) def extended_gcd(a, b): if b == 0: return (a, 1, 0) else: d, x, y = extended_gcd(b, a % b) return (d, y, x - (a // b) * y) def mod_inverse(a, m): d, x, y = extended_gcd(a, m) if d != 1: raise ValueError("No inverse exists") else: return x % m def generate_key_pair(p, q): n = p * q phi = (p - 1) * (q - 1) e = random.randrange(1, phi) while gcd(e, phi) != 1: e = random.randrange(1, phi) d = mod_inverse(e, phi) return ((n, e), (n, d)) def encrypt(msg, public_key): n, e = public_key m = int.from_bytes(msg.encode(), 'big') c = pow(m, e, n) return c.to_bytes((c.bit_length() + 7) // 8, 'big').decode() def decrypt(cipher, private_key): n, d = private_key c = int.from_bytes(cipher.encode(), 'big') m = pow(c, d, n) return m.to_bytes((m.bit_length() + 7) // 8, 'big').decode() # 选择两个大素数 p 和 q p = 61 q = 53 # 生成公钥和私钥 public_key, private_key = generate_key_pair(p, q) print("公钥:", public_key) print("私钥:", private_key) # 加密和解密 msg = "Hello, world!" cipher = encrypt(msg, public_key) print("密文:", cipher) plaintext = decrypt(cipher, private_key) print("明文:", plaintext) ``` 需要注意的是,由于 RSA 加密算法使用了大整数计算,因此在处理大数时需要使用适当的库来避免溢出等问题。在 Python 中,可以使用内置的 `pow()` 函数来计算幂取模,也可以使用第三方库(如 `gmpy2` )来进行大整数运算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值