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); }