RSA 数据加签验签 & 加密解密 - 附完整代码&注释

RSA 数据加签验签 && 加密解密

简介

  • RSA是一种非对称加密算法,它是由Rivest-Shamir-Adleman三位密码学家于1978年提出的。

  • RSA算法的加密规则如下:

    • 钥匙生成:RSA算法使用两个密钥,一个是公钥(public key),用于加密数据,另一个是私钥(private key),用于解密数据。首先,密钥生成者生成一对公钥和私钥,其中公钥可以公开给任何人使用,而私钥必须保密。

    • 加密过程:发送方使用接收方的公钥对数据进行加密。发送方将数据按照一定的规则进行转换,并使用公钥进行加密操作。加密后的数据将无法直接被解密,只能使用私钥才能将其解密。

    • 解密过程:接收方使用自己的私钥对加密后的数据进行解密。接收方使用私钥对加密后的数据进行解密操作,从而得到原始的明文数据。

  • 参考:JAVA 使用RSA算法进行数字签名验证

代码

  • 公钥私钥是唯一一对 可以使用公钥加密私钥解密也可以使用私钥加密公钥解密 看自己需求。
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @Author: 小新
 * @Date: 2024/4/3 9:56
 *  RSA 数据加签验签 加密解密
 */
public class RSAUtil {
    private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class);

    private String privateKey;
    private String publicKey;

    public static void main(String[] args) {
        Entity entity = new Entity();
        // 使用RSA算法生成 公钥与私钥, 生成的公私钥 是一一对应的。
        createRSAKey(entity);
        String body = "加签";
        // 将入参数据以及私钥进行数字加签
        String sign = sign(body, entity.getPrivateKey());
        // 根据入参数据以及公钥进行验证签名,若入参数据body被修改或者秘钥不正确都会导致验签失败;例如加签使用body,验签使用body2则导致验签失败
        boolean verifyFlag = verify(body,entity.getPublicKey(), sign);
        if (verifyFlag) {
            logger.info("验签成功");
        } else {
            logger.info("验签失败");
        }
    }

    /**
     * 生成对应的 与我通信的公钥和私钥
     * @return
     */
    public static void createRSAKey(Entity entity) {
        try {
            // 创建KeyPairGenerator 指定算法为RSA,用于生成对应的公钥和私钥
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            // 指定字节长度
            keyPairGenerator.initialize(1024);
            // 秘钥生成器
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 公钥
            RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
            // 进行Base64编码存入
            String clientPublicKey = Base64.encodeBase64String(publicKey.getEncoded());
            logger.info("生成的clientPublicKey是: {}", clientPublicKey);
            entity.setPublicKey(clientPublicKey);
            // 私钥
            RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
            // 进行Base64编码存入
            String clientPrivateKey = Base64.encodeBase64String(privateKey.getEncoded());
            logger.info("生成的clientPrivateKey是: {}", clientPrivateKey);
            entity.setPrivateKey(clientPrivateKey);
        } catch (Exception e) {
            logger.error("生成秘钥失败");
            e.printStackTrace();
        }
    }

    /**
     * 利用私钥信息生成数字签名
     * @param data 入参数据body
     * @param privateKey 私钥
     * @return
     */
    public static String sign(String data, String privateKey) {
        try {
            // 入参数据body字节数组
            byte[] dataBytes = data.getBytes();
            // 获取私钥秘钥字节数组
            byte[] keyBytes = Base64.decodeBase64(privateKey);
            // 使用给定的编码密钥创建一个新的PKCS8EncodedKeySpec。
            // PKCS8EncodedKeySpec 是 PKCS#8标准作为密钥规范管理的编码格式
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            // 实例化KeyFactory,指定为加密算法 为 RSA
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 获得PrivateKey对象
            PrivateKey privateKey1 = keyFactory.generatePrivate(keySpec);
            // 用私钥对信息生成数字签名,指定签名算法为 MD5withRSA
            Signature signature = Signature.getInstance("MD5withRSA");
            // 初始化签名
            signature.initSign(privateKey1);
            // 数据body带入
            signature.update(dataBytes);
            // 对签名进行Base64编码
            return Base64.encodeBase64String(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 利用公钥校验数字签名
     * @param data 入参数据body
     * @param publicKey 公钥
     * @param sign 签名
     * @return
     */
    public static boolean verify(String data, String publicKey, String sign) {
        try {
            // 入参数据body字节数组
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            // 获取公钥秘钥字节数组
            byte[] keyBytes = Base64.decodeBase64(publicKey);
            // 使用给定的编码密钥创建一个新的X509EncodedKeySpec
            // X509EncodedKeySpec是基于X.509证书提前的公钥,一种java秘钥规范
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
            // 实例化KeyFactory,指定为加密算法 为 RSA
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 获取publicKey对象
            PublicKey publicKey1 = keyFactory.generatePublic(x509EncodedKeySpec);
            // 用私钥对信息生成数字签名,指定签名算法为 MD5withRSA
            Signature signature = Signature.getInstance("MD5withRSA");
            // 带入公钥进行验证
            signature.initVerify(publicKey1);
            // 数据body带入
            signature.update(dataBytes);
            // 验证签名
            return signature.verify(Base64.decodeBase64(sign));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 使用公钥对明文进行加密
     *
     * @param plainText 明文字符串
     * @param publicKey 公钥字符串(Base64编码)
     * @return 加密后的数据(字节数组形式)
     * @throws Exception 加密过程中发生的异常
     */
    public static byte[] encryptWithPublicKey(String plainText, String publicKey) throws Exception {
        // 解码公钥字符串
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        // 生成X509EncodedKeySpec
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        // 实例化KeyFactory并指定为RSA
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        // 生成PublicKey对象
        PublicKey rsaPublicKey = keyFactory.generatePublic(keySpec);
        // 实例化Cipher并指定为RSA/ECB/PKCS1Padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        // 使用公钥初始化Cipher为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
        // 执行加密操作
        return cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 使用私钥对密文进行解密
     *
     * @param encryptedData 加密后的数据(字节数组形式)
     * @param privateKey    私钥字符串(Base64编码)
     * @return 解密后的明文字符串
     * @throws Exception 解密过程中发生的异常
     */
    public static String decryptWithPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
        // 解码私钥字符串
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        // 生成PKCS8EncodedKeySpec
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        // 实例化KeyFactory并指定为RSA
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        // 生成PrivateKey对象
        PrivateKey rsaPrivateKey = keyFactory.generatePrivate(keySpec);
        // 实例化Cipher并指定为RSA/ECB/PKCS1Padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        // 使用私钥初始化Cipher为解密模式
        cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
        // 执行解密操作
        byte[] decryptedBytes = cipher.doFinal(encryptedData);
        // 将解密后的字节数组转换为字符串(使用UTF-8编码)
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 使用私钥对数据进行加密
     *
     * @param data 明文数据(字符串形式)
     * @param privateKey 私钥字符串(Base64编码)
     * @return 加密后的密文(字节数组)
     * @throws Exception 加密过程中发生的异常
     */
    public static byte[] encryptWithPrivateKey(String data, String privateKey) throws Exception {
        // 解码私钥字符串
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        // 生成PKCS8EncodedKeySpec
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        // 实例化KeyFactory并指定为RSA
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        // 生成PrivateKey对象
        PrivateKey rsaPrivateKey = keyFactory.generatePrivate(keySpec);
        // 实例化Cipher并指定为RSA/ECB/PKCS1Padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        // 使用私钥初始化Cipher为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, rsaPrivateKey);
        // 执行加密操作
        return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 使用公钥对数据进行解密
     *
     * @param encryptedData 加密后的数据(字节数组形式)
     * @param publicKey 公钥字符串(Base64编码)
     * @return 解密后的明文数据(字符串)
     * @throws Exception 解密过程中发生的异常
     */
    public static String decryptWithPublicKey(byte[] encryptedData, String publicKey) throws Exception {
        // 解码公钥字符串
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        // 生成X509EncodedKeySpec
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        // 实例化KeyFactory并指定为RSA
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        // 生成PublicKey对象
        PublicKey rsaPublicKey = keyFactory.generatePublic(keySpec);
        // 实例化Cipher并指定为RSA/ECB/PKCS1Padding
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        // 使用公钥初始化Cipher为解密模式
        cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
        // 执行解密操作
        byte[] decryptedBytes = cipher.doFinal(encryptedData);
        // 将解密后的字节数组转换为字符串(使用UTF-8编码)
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用C语言和OpenSSL编写RSA加密解密算法的代码及注释: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/rsa.h> #define KEY_LENGTH 2048 // RSA密钥长度 #define PUB_EXP 3 // RSA公钥指数 // RSA密钥对结构体 typedef struct _rsa_keys { RSA *public_key; RSA *private_key; } rsa_keys; // 生成RSA密钥对函数 int generate_rsa_keys(rsa_keys *keys) { int ret = 0; BIGNUM *bn = NULL; BIO *bio = NULL; // 生成RSA密钥对 keys->public_key = RSA_new(); keys->private_key = RSA_new(); bn = BN_new(); ret = BN_set_word(bn, PUB_EXP); ret = RSA_generate_key_ex(keys->public_key, KEY_LENGTH, bn, NULL); ret = RSA_generate_key_ex(keys->private_key, KEY_LENGTH, bn, NULL); // 清除内存 BN_free(bn); return ret; } // RSA密函数 int rsa_encrypt(char *input, int input_len, char *output, rsa_keys *keys) { int ret = 0; BIO *bio = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; size_t output_len = 0; // 获取RSA公钥 pkey = EVP_PKEY_new(); ret = EVP_PKEY_set1_RSA(pkey, keys->public_key); // 创建RSA密上下文 ctx = EVP_PKEY_CTX_new(pkey, NULL); // 初始化RSA密上下文 ret = EVP_PKEY_encrypt_init(ctx); // 设置RSA密填充模式 ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); // 执行RSA密 ret = EVP_PKEY_encrypt(ctx, NULL, &output_len, input, input_len); // 申请内存 output = (char*) malloc(output_len); // 执行RSA密 ret = EVP_PKEY_encrypt(ctx, output, &output_len, input, input_len); // 清除内存 EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return ret; } // RSA解密函数 int rsa_decrypt(char *input, int input_len, char *output, rsa_keys *keys) { int ret = 0; BIO *bio = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; size_t output_len = 0; // 获取RSA私钥 pkey = EVP_PKEY_new(); ret = EVP_PKEY_set1_RSA(pkey, keys->private_key); // 创建RSA解密上下文 ctx = EVP_PKEY_CTX_new(pkey, NULL); // 初始化RSA解密上下文 ret = EVP_PKEY_decrypt_init(ctx); // 设置RSA解密填充模式 ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); // 执行RSA解密 ret = EVP_PKEY_decrypt(ctx, NULL, &output_len, input, input_len); // 申请内存 output = (char*) malloc(output_len); // 执行RSA解密 ret = EVP_PKEY_decrypt(ctx, output, &output_len, input, input_len); // 清除内存 EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return ret; } int main() { rsa_keys keys; char *input = "Hello, RSA!"; char *encrypted = NULL; char *decrypted = NULL; int ret = 0; // 生成RSA密钥对 ret = generate_rsa_keys(&keys); // RSA密 ret = rsa_encrypt(input, strlen(input), encrypted, &keys); // RSA解密 ret = rsa_decrypt(encrypted, strlen(encrypted), decrypted, &keys); // 输出结果 printf("Input: %s\n", input); printf("Encrypted: %s\n", encrypted); printf("Decrypted: %s\n", decrypted); // 清除内存 free(encrypted); free(decrypted); return 0; } ``` 注释已经标注在代码中,主要分为以下几个部分: - 生成RSA密钥对 - RSA密 - RSA解密 代码中使用了OpenSSL库提供的RSA相关函数。首先使用`RSA_new()`函数创建RSA密钥对结构体,然后使用`RSA_generate_key_ex()`函数生成RSA密钥对。生成RSA密钥对后,使用`EVP_PKEY_set1_RSA()`函数获取RSA公钥或私钥,使用`EVP_PKEY_CTX_new()`函数创建RSA密或解密上下文,使用`EVP_PKEY_encrypt()`或`EVP_PKEY_decrypt()`函数执行RSA密或解密,最后使用`EVP_PKEY_CTX_free()`和`EVP_PKEY_free()`函数清除内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值