Java RSA 加解密,生成,签名与C# 互通

前言

最近一段时间发现C# 本身加密的库 与JAVA 的RSA加密 不能互通

具体体现在公钥不能加密,无法使用pkcs#8

可以使用 BouncyCastle .net 版 ,但是这个库的文档非常难找,官网的案例写的又不是我需要的东西,我艰难的把这个接近等效的过程记录下来了,有什么问题

于是把这个艰难的过程记录下来供大家参考

java 代码

Java 环境使用Java 8

maven部分:

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.3</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.27</version>
</dependency>

 

 

import部分

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

import cn.hutool.json.JSONObject;

 

const:

 /**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /**
     * 获取公钥的key
     */
    private static final String PUBLIC_KEY = "RSAPublicKey";

    /**
     * 获取私钥的key
     */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * RSA最大加密明文大小 117
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

 

生成密钥:

    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

 

私钥产生签名:

public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decode(privateKey.getBytes());
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return new String(Base64.encode(signature.sign()));        
    }

 

公钥验证签名:

public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
        byte[] keyBytes = BaseUtils.decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(BaseUtils.decode(sign));
    }

 

分段加密函数:

private static byte[] getByteArray(byte[] data, Cipher cipher, int maxBlockSize)
            throws IllegalBlockSizeException, BadPaddingException, IOException {
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > maxBlockSize) {
                cache = cipher.doFinal(data, offSet, maxBlockSize);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * maxBlockSize;
        }
        byte[] endeData = out.toByteArray();
        out.close();
        return endeData;
    }

 

私钥加密:

public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
            throws Exception {
        byte[] keyBytes = BaseUtils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        return getByteArray(data, cipher, MAX_ENCRYPT_BLOCK);
    }

 

私钥解密:

public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
            throws Exception {
        byte[] keyBytes = BaseUtils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        return getByteArray(encryptedData, cipher, MAX_DECRYPT_BLOCK);
    }

 

公钥加密:

public static byte[] encryptByPublicKey(byte[] data, String publicKey)
            throws Exception {
        byte[] keyBytes = BaseUtils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        return getByteArray(data, cipher, MAX_ENCRYPT_BLOCK);
    }

 

公钥解密:

public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
            throws Exception {
        byte[] keyBytes = BaseUtils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        return getByteArray(encryptedData, cipher, MAX_DECRYPT_BLOCK);
    }

 

C# 代码部分

包引用:

生成密钥:

public static Dictionary<String, AsymmetricKeyParameter> genKeyPair()
 {
     var random = new SecureRandom();
     var keyGenerationParameters = new KeyGenerationParameters(random, 1024);
     RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
     generator.Init(keyGenerationParameters);
     Dictionary<string, AsymmetricKeyParameter> obj = new();
     var keyPair = generator.GenerateKeyPair();
     obj.Add(PUBLIC_KEY, keyPair.Public);
     obj.Add(PRIVATE_KEY, keyPair.Private);           
     return obj;
 }

 

const:

特别说明C# 加密解密算法 字符串描述不能省略 padding Java RSA默认使用 pkcs#1 padding ,保存密码默认使用PKCS#8

/// <summary>
 /// 签名算法
 /// </summary>
  public const String SIGNATURE_ALGORITHM = "MD5withRSA";
/// <summary>
/// 
/// </summary>
  private const String PUBLIC_KEY = "RSAPublicKey";
 /// <summary>
 /// C# 不能省略padding
 /// </summary>
  public const String KEY_ALGORITHM = "RSA//PKCS1PADDING";
 /// <summary>
 /// 
 /// </summary>
  private const String PRIVATE_KEY = "RSAPrivateKey";
 /// <summary>
 /// 加密块
 /// </summary>
  private static readonly int MAX_ENCRYPT_BLOCK = 117;

 /// <summary>
 /// 解密块
 /// </summary>
  private static readonly int MAX_DECRYPT_BLOCK = 128;

 

私钥产生签名:

 public static String sign(Byte[] data, String privateKey)
 {
     var paramters = PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
     /* Make the key */
     //RsaKeyParameters key = MakeKey(privateModulusHexString, privateExponentHexString, true);

     /* Init alg */
     ISigner sig = SignerUtilities.GetSigner(SIGNATURE_ALGORITHM);

     /* Populate key */
     sig.Init(true, paramters);

     /* Get the bytes to be signed from the string */
     var bytes =data;

     /* Calc the signature */
     sig.BlockUpdate(bytes, 0, bytes.Length);
     byte[] signature = sig.GenerateSignature();

     /* Base 64 encode the sig so its 8-bit clean */
     var signedString = Convert.ToBase64String(signature);

     return signedString;
 }

 

公钥验证签名:

 public static bool verify(byte[] data, String publicKey, String sign)
 {
     /* Make the key */
     var paramters = PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));

     /* Init alg */
     var signer = SignerUtilities.GetSigner(SIGNATURE_ALGORITHM);

     /* Populate key */
     signer.Init(false, paramters);

     /* Get the signature into bytes */
     var expectedSig = Convert.FromBase64String(sign);

     /* Get the bytes to be signed from the string */
     var msgBytes = data;

     /* Calculate the signature and see if it matches */
     signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
     return signer.VerifySignature(expectedSig);
 }

 

分段加密函数:

 private static byte[] getByteArray(byte[] data, IBufferedCipher cipher, int maxBlockSize)
     {
         int inputLen = data.Length;
         MemoryStream outdatas = new(inputLen);
         int offSet = 0;
         byte[] cache;
         int i = 0;
         // 对数据分段解密
         while (inputLen - offSet > 0)
         {
             if (inputLen - offSet > maxBlockSize)
             {
                 cache = cipher.DoFinal(data, offSet, maxBlockSize);
             }
             else
             {
                 cache = cipher.DoFinal(data, offSet, inputLen - offSet);
             }
             outdatas.Write(cache, 0, cache.Length);
             i++;
             offSet = i * maxBlockSize;
         }
         byte[] endeData = outdatas.ToArray();
         outdatas.Close();
         return endeData;
     }

 

私钥加密:

 public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
 {
     RsaKeyParameters privateKeyParam = (RsaKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
     var cipher = CipherUtilities.GetCipher(KEY_ALGORITHM);

     cipher.Init(true, privateKeyParam);
     /* IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
      engine.Init(true, GetPrivateKeyParameter(privateKey));*/

     return getByteArray(data, cipher, MAX_ENCRYPT_BLOCK);
 }

 

私钥解密:

 public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
 {
     RsaKeyParameters privateKeyParam = (RsaKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
     var cipher = CipherUtilities.GetCipher(KEY_ALGORITHM);

     cipher.Init(false, privateKeyParam);
     return getByteArray(encryptedData, cipher, MAX_DECRYPT_BLOCK);
 }

 

公钥加密:

public static byte[] EncryptByPublicKey(byte[] data, String publicKey)
 {
     RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
     //var original = new BigInteger(Encoding.UTF8.GetBytes(content));
     var cipher = CipherUtilities.GetCipher(KEY_ALGORITHM);

     cipher.Init(true, publicKeyParam);

     var endatas = getByteArray(data,cipher,MAX_ENCRYPT_BLOCK);
     return endatas;


 }

 

公钥解密:

public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
{
    RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
    //var original = new BigInteger(Encoding.UTF8.GetBytes(content));
    var cipher = CipherUtilities.GetCipher(KEY_ALGORITHM);
    //var cipher = CipherUtilities.GetCipher(KEY_ALGORITHM);
    cipher.Init(false, publicKeyParam);
    return getByteArray(encryptedData, cipher, MAX_DECRYPT_BLOCK);
}

 

posted @ 2024-05-26 20:24  血色双眸  阅读(378)  评论(1)    收藏  举报