【加解密】报文签名与加解密,MD5,RSA,AES使用案例(基于 Java)

需要考虑哪些问题?

在进行报文传输时,有两个问题需要考虑:

  1. 消息防篡改
  2. 加密报文

定义消息结构

为了方便后面使用,这里定义消息结构:

public static class Message {
    public String data; //消息
    public String sign; //签名

    public Message(String data, String sign) {
        this.data = data;
        this.sign = sign;
    }
}

对报文进行签名

首先我们假设消息是一个字符串:String msg = "Hello, message encryption!"

然后我们对这个报文计算摘要:byte[] msgHash = md5(msg)。只要两个字符串计算出的摘要相同,我们认为这两个字符串是相等的(即没有被篡改过)。

然而如果直接传输 msg 及其摘要,那么很容易被别人篡改,这时就需要对摘要进行加密,也就是所谓的签名。也就是防止篡改的核心。下面给出一个完整的实现:

这里只放主要流程,辅助方法见附录:

// 生成RSA密钥对
KeyPair keyPair = generateKeyPair();

// 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

// 要加密的原始数据
String originalMessage = "Hello, message encryption!";

//发送端签名
Message message = sign(originalMessage, privateKey);
System.out.println("加密后的消息签名: " + message.sign);

//接收端校验签名
boolean checkResult = checkSign(message, publicKey);
System.out.println("合法:" + checkResult);

对报文进行加密

在发送端: 首先生成 AES 密钥,使用AES对报文进行加密,然后使用 RSA 对 AES 密钥进行加密。(考虑到报文本身可能较大,而非对称RSA加密效率较差)

在接收端:使用 RSA解密 AES 密钥,使用解密的 AES 密钥解密报文。

// 生成RSA密钥对
KeyPair keyPair = generateKeyPair();

// 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

//生成 aes 密钥
byte[] aesKey = generateAesKey();
//使用公钥对 aes 密钥进行加密
byte[] encryptedAesKey = encrypt(aesKey, publicKey);

//报文
String originalMessage = "Hello, message encryption!";

// 使用AES密钥加密报文
byte[] encryptedMessage = encryptWithAes(originalMessage.getBytes(), aesKey);

//将encryptedAesKey和encryptedMessage传给接收端
// 使用私钥解密AES密钥
byte[] decryptedAesKey = decrypt(encryptedAesKey, privateKey);

// 使用AES密钥解密消息
String decryptedMessage = new String(decryptWithAes(encryptedMessage, decryptedAesKey));

附录

//公钥签名
public static Message sign(String originalMessage, PublicKey publicKey) throws Exception {
    byte[] bytes = calculateMD5(originalMessage);
    byte[] encryptedHash = encrypt(bytes, publicKey);
    String signStr = bytesToHex(encryptedHash);
    return new Message(originalMessage, signStr);
}

//私钥签名
public static Message sign(String originalMessage, PrivateKey privateKey) throws Exception {
    byte[] bytes = calculateMD5(originalMessage);
    byte[] encryptedHash = encrypt(bytes, privateKey);
    String signStr = bytesToHex(encryptedHash);
    return new Message(originalMessage, signStr);
}

//公钥验签
public static boolean checkSign(Message message, PublicKey publicKey) throws Exception {
    byte[] sign = hexToBytes(message.sign);
    byte[] md5Hash = decrypt(sign, publicKey);
    byte[] calcMd5Hash = calculateMD5(message.data);
    return Arrays.equals(md5Hash, calcMd5Hash);
}

//私钥验签
public static boolean checkSign(Message message, PrivateKey privateKey) throws Exception {
    byte[] sign = hexToBytes(message.sign);
    byte[] md5Hash = decrypt(sign, privateKey);
    byte[] calcMd5Hash = calculateMD5(message.data);
    return Arrays.equals(md5Hash, calcMd5Hash);
}

// 生成RSA密钥对
public static KeyPair generateKeyPair() throws Exception {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    SecureRandom secureRandom = new SecureRandom();
    keyPairGenerator.initialize(2048, secureRandom);
    return keyPairGenerator.generateKeyPair();
}

// 计算MD5哈希值
public static byte[] calculateMD5(String message) throws Exception {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(message.getBytes());
    return md.digest();
}

// 使用公钥加密数据
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    return cipher.doFinal(data);
}

// 使用私钥加密数据
public static byte[] encrypt(byte[] data, PrivateKey privateKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    return cipher.doFinal(data);
}

// 使用公钥解密数据
public static byte[] decrypt(byte[] data, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, publicKey);
    return cipher.doFinal(data);
}

// 使用私钥解密数据
public static byte[] decrypt(byte[] data, PrivateKey privateKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    return cipher.doFinal(data);
}

// 生成AES密钥
public static byte[] generateAesKey() throws Exception {
    SecureRandom secureRandom = new SecureRandom();
    byte[] key = new byte[16];
    secureRandom.nextBytes(key);
    return key;
}

// 使用AES密钥加密数据
public static byte[] encryptWithAes(byte[] data, byte[] key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
    return cipher.doFinal(data);
}

// 使用AES密钥解密数据
public static byte[] decryptWithAes(byte[] encryptedData, byte[] key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
    return cipher.doFinal(encryptedData);
}

// 将字节数组转换为十六进制字符串
public static String bytesToHex(byte[] bytes) {
    StringBuilder hexString = new StringBuilder();
    for (byte b : bytes) {
        String hex = Integer.toHexString(0xff & b);
        if (hex.length() == 1) {
            hexString.append('0');
        }
        hexString.append(hex);
    }
    return hexString.toString();
}

public static byte[] hexToBytes(String hex) {
    int len = hex.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                + Character.digit(hex.charAt(i + 1), 16));
    }
    return data;
}
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值