在 Java 中工作的 RSA 加密中但不使用 c# 加密?
In RSA Encrypting working in Java but not working with encrypting from c#?
RSA 加密和解密在 java 方面工作良好,模数和指数如下:
Java RSA 模数和指数:
String nModulusPublic = "AJ+L/dVL9jnRX6IM87H8x2fR24t6wpzBDV7bcgPWblegR0LNK91z/OSX+lSLUgHSKJ9to/Eo8OMsREpNoJlEzI0=";
String eExponentPublic = "AQAB";
String eExponentPrivate = "AIpmE5C9TiAlgYG/Hn5dOlTS9FFv8fWseX65eZPepOUY4ivxN0lOZ+MsugZd03wmKvnxBuCGu5nv2qrUBTPzjcE=";
Java Public 和私钥生成器:
static PublicKey GetPublicKey(String publicKString, String publicExponentStr) throws Exception {
byte[] modulusBytes = Base64.getDecoder().decode(publicKString);
byte[] exponentBytes = Base64.getDecoder().decode(publicExponentStr);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
return pubKey;
}
static PrivateKey GetPrivateKey(String nModulusPublic, String eExponentPrivate) throws Exception {
byte[] modulusBytes = Base64.getDecoder().decode(nModulusPublic);
byte[] exponentBytes = Base64.getDecoder().decode(eExponentPrivate);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(privSpec);
return privKey;
}
我在 c# 中使用 nModulusPublic 和 eExponentPublic 在 Java 中加密和解密,但不起作用。
致力于 RSA.Encrypt(textBytes, true); c# 函数中的参数将其更改为 false 和 RSAEncryptionPadding.Pkcs1 但不起作用。当我使用 java 中的 c# Encrypt 函数的结果进行解密时,总是会遇到此错误:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 64 bytes
C# 加密函数:
static string Encrypt(string text)
{
string outputB64 = string.Empty;
byte[] textBytes = Encoding.UTF8.GetBytes(text);
RSAParameters result = new RSAParameters()
{
Modulus = Convert.FromBase64String(nModulusPublic),
Exponent = Convert.FromBase64String(eExponentPublic)
};
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSA.ImportParameters(result);
byte[] encryptedData = RSA.Encrypt(textBytes, true);
outputB64 = Convert.ToBase64String(encryptedData);
}
return outputB64;
}
额外信息,Java加密和解密主要函数:
static String Decrypt(String encodedString,PrivateKey privKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encodedString));
return new String(decrypted, "UTF-8");
} catch (Exception err) {
return err.fillInStackTrace().toString();
}
}
static String Encrypt(String encodedString,PublicKey pubKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String(encodedString).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedString = Base64.getEncoder().encodeToString(cipherData);
return encryptedString;
} catch (Exception err) {
return err.fillInStackTrace().toString();
}
}
更新:
我正在研究它,发现 java 加密函数和 c# 有两种不同的类型,Java 结果总是以“==”结尾,但 c# 函数有一个“=”完了,好像是这个问题。
C# 加密函数结果:
AJiltxqa1/8HU20XZlKJsJvclQ8PyQetpWdbCOpbqrXVg0q
/v4x5tXLxbzGKbO5InvKkib7tDQp+9BU0SYbZLv0=
Java 加密函数结果:
RlarFQBo2mcCWjidQ5l7ho2EOG6KGQWpR3ByXXHsGo6+HRQzmO4v7
TUTMdfB9wjI3aO6quruSReitrWu7QF9Vw==
在 C# 加密函数上,你给参数 'true':
byte[] encryptedData = RSA.Encrypt(textBytes, true);
这意味着 C# 使用的不是 PKCS1Padding,而是 OEAPPadding。
只需在 Decrypt-method(以及 ENCRYPT-method 中的 Java-side 上更改 Java-side 行
// change:
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// to
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
我用你的密钥对测试了它,它像预期的那样工作。
编辑:
在 C# 端,我 运行 此代码:
string plaintext = "The quick brown fox";
string encryptedDataBase64So = Encrypt(plaintext);
Console.WriteLine("encrypted SO : " + encryptedDataBase64So);
Console output:
encrypted SO : ZLylMsqcqbuDM7DprrmqIU8c8Q79fPXHudOY4INCNAo+iU7Oor3mZ8i+PP5PjtDkifqAXKYT8ON/ia9WjEFqRQ==
在 Java-side 我将 base64 字符串作为输入:
String fromCsharp = "Ew3nTEQuOX1tWfRNJEERa75A1o2bn6+HurVPYzGzA7kt+HAZAMdXKNACY2emvU6Bf42i8zpBO89lqvzuxNmRIw==";
String decryptedtext = DecryptWorking(fromCsharp, privateKey);
System.out.println("\ndecrypted from c#: " + decryptedtext);
Console output:
decrypted from c#: The quick brown fox
顺便说一句:这是我从 Java-side 上的 PublicKey 生成的 C# 端的 PublicKey,并像这样用作 RSA-Encryption:
的源
var publicKey = "<RSAKeyValue><Modulus>n4v91Uv2OdFfogzzsfzHZ9Hbi3rCnMENXttyA9ZuV6BHQs0r3XP85Jf6VItSAdIon22j8Sjw4yxESk2gmUTMjQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
RSA.FromXmlString(publicKey);
除了 Michael Fehr 的 中详细描述的填充错误之外,还有另一个问题实际上是导致错误消息 IllegalBlockSizeException: Data must not be longer than 64 bytes. 如果不首先抛出 IllegalBlockSizeException,则不一致的填充将抛出 BadPaddingException。
发布的密文有前导 0 字节,因此大小为 65 字节:
Base64: AJiltxqa1/8HU20XZlKJsJvclQ8PyQetpWdbCOpbqrXVg0q/v4x5tXLxbzGKbO5InvKkib7tDQp+9BU0SYbZLv0=
Hex: 0098a5b71a9ad7ff07536d17665289b09bdc950f0fc907ada5675b08ea5baab5d5834abfbf8c79b572f16f318a6cee489ef2a489beed0d0a7ef415344986d92efd
如果您尝试在 Java 端解密此密文,您将收到发布的错误:IllegalBlockSizeException:数据不得超过 64 字节。
为什么C#代码会产生太长的密文?这是因为模数也有前导 0 字节,因此长度为 65 字节:
Base64: AJ+L/dVL9jnRX6IM87H8x2fR24t6wpzBDV7bcgPWblegR0LNK91z/OSX+lSLUgHSKJ9to/Eo8OMsREpNoJlEzI0=
Hex: 009f8bfdd54bf639d15fa20cf3b1fcc767d1db8b7ac29cc10d5edb7203d66e57a04742cd2bdd73fce497fa548b5201d2289f6da3f128f0e32c444a4da09944cc8d
模数是用BigInteger.toByteArray()
(see 导出的,更新部分),其中returns两个's-complement表示并放置一个前导0如果最前面的字节的值大于 0x7f,则前面的字节。
模数中的前导 0 字节导致由 C# 代码生成的密文,它也有前导 0 字节,因此 65 字节的长度无效。这没有多大意义,可能是一个错误。
要解决此问题,应为 C# 代码删除模数中的 0 字节,从而产生以下 Base64 编码模数(将产生 64 字节密文):
n4v91Uv2OdFfogzzsfzHZ9Hbi3rCnMENXttyA9ZuV6BHQs0r3XP85Jf6VItSAdIon22j8Sjw4yxESk2gmUTMjQ==
也可以去掉密文中的0字节,得到如下密文(Base64编码):
mKW3GprX/wdTbRdmUomwm9yVDw/JB62lZ1sI6luqtdWDSr+/jHm1cvFvMYps7kie8qSJvu0NCn70FTRJhtku/Q==
现在可以通过 Java 代码成功解密为明文(如果应用了一致的填充,请参阅 Michael Fehr 的 ):
Davood
RSA 加密和解密在 java 方面工作良好,模数和指数如下:
Java RSA 模数和指数:
String nModulusPublic = "AJ+L/dVL9jnRX6IM87H8x2fR24t6wpzBDV7bcgPWblegR0LNK91z/OSX+lSLUgHSKJ9to/Eo8OMsREpNoJlEzI0=";
String eExponentPublic = "AQAB";
String eExponentPrivate = "AIpmE5C9TiAlgYG/Hn5dOlTS9FFv8fWseX65eZPepOUY4ivxN0lOZ+MsugZd03wmKvnxBuCGu5nv2qrUBTPzjcE=";
Java Public 和私钥生成器:
static PublicKey GetPublicKey(String publicKString, String publicExponentStr) throws Exception {
byte[] modulusBytes = Base64.getDecoder().decode(publicKString);
byte[] exponentBytes = Base64.getDecoder().decode(publicExponentStr);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
return pubKey;
}
static PrivateKey GetPrivateKey(String nModulusPublic, String eExponentPrivate) throws Exception {
byte[] modulusBytes = Base64.getDecoder().decode(nModulusPublic);
byte[] exponentBytes = Base64.getDecoder().decode(eExponentPrivate);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(privSpec);
return privKey;
}
我在 c# 中使用 nModulusPublic 和 eExponentPublic 在 Java 中加密和解密,但不起作用。 致力于 RSA.Encrypt(textBytes, true); c# 函数中的参数将其更改为 false 和 RSAEncryptionPadding.Pkcs1 但不起作用。当我使用 java 中的 c# Encrypt 函数的结果进行解密时,总是会遇到此错误:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 64 bytes
C# 加密函数:
static string Encrypt(string text)
{
string outputB64 = string.Empty;
byte[] textBytes = Encoding.UTF8.GetBytes(text);
RSAParameters result = new RSAParameters()
{
Modulus = Convert.FromBase64String(nModulusPublic),
Exponent = Convert.FromBase64String(eExponentPublic)
};
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSA.ImportParameters(result);
byte[] encryptedData = RSA.Encrypt(textBytes, true);
outputB64 = Convert.ToBase64String(encryptedData);
}
return outputB64;
}
额外信息,Java加密和解密主要函数:
static String Decrypt(String encodedString,PrivateKey privKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encodedString));
return new String(decrypted, "UTF-8");
} catch (Exception err) {
return err.fillInStackTrace().toString();
}
}
static String Encrypt(String encodedString,PublicKey pubKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String(encodedString).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedString = Base64.getEncoder().encodeToString(cipherData);
return encryptedString;
} catch (Exception err) {
return err.fillInStackTrace().toString();
}
}
更新:
我正在研究它,发现 java 加密函数和 c# 有两种不同的类型,Java 结果总是以“==”结尾,但 c# 函数有一个“=”完了,好像是这个问题。
C# 加密函数结果:
AJiltxqa1/8HU20XZlKJsJvclQ8PyQetpWdbCOpbqrXVg0q
/v4x5tXLxbzGKbO5InvKkib7tDQp+9BU0SYbZLv0=
Java 加密函数结果:
RlarFQBo2mcCWjidQ5l7ho2EOG6KGQWpR3ByXXHsGo6+HRQzmO4v7
TUTMdfB9wjI3aO6quruSReitrWu7QF9Vw==
在 C# 加密函数上,你给参数 'true':
byte[] encryptedData = RSA.Encrypt(textBytes, true);
这意味着 C# 使用的不是 PKCS1Padding,而是 OEAPPadding。
只需在 Decrypt-method(以及 ENCRYPT-method 中的 Java-side 上更改 Java-side 行
// change:
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// to
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
我用你的密钥对测试了它,它像预期的那样工作。
编辑: 在 C# 端,我 运行 此代码:
string plaintext = "The quick brown fox";
string encryptedDataBase64So = Encrypt(plaintext);
Console.WriteLine("encrypted SO : " + encryptedDataBase64So);
Console output:
encrypted SO : ZLylMsqcqbuDM7DprrmqIU8c8Q79fPXHudOY4INCNAo+iU7Oor3mZ8i+PP5PjtDkifqAXKYT8ON/ia9WjEFqRQ==
在 Java-side 我将 base64 字符串作为输入:
String fromCsharp = "Ew3nTEQuOX1tWfRNJEERa75A1o2bn6+HurVPYzGzA7kt+HAZAMdXKNACY2emvU6Bf42i8zpBO89lqvzuxNmRIw==";
String decryptedtext = DecryptWorking(fromCsharp, privateKey);
System.out.println("\ndecrypted from c#: " + decryptedtext);
Console output:
decrypted from c#: The quick brown fox
顺便说一句:这是我从 Java-side 上的 PublicKey 生成的 C# 端的 PublicKey,并像这样用作 RSA-Encryption:
的源var publicKey = "<RSAKeyValue><Modulus>n4v91Uv2OdFfogzzsfzHZ9Hbi3rCnMENXttyA9ZuV6BHQs0r3XP85Jf6VItSAdIon22j8Sjw4yxESk2gmUTMjQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
RSA.FromXmlString(publicKey);
除了 Michael Fehr 的
发布的密文有前导 0 字节,因此大小为 65 字节:
Base64: AJiltxqa1/8HU20XZlKJsJvclQ8PyQetpWdbCOpbqrXVg0q/v4x5tXLxbzGKbO5InvKkib7tDQp+9BU0SYbZLv0= Hex: 0098a5b71a9ad7ff07536d17665289b09bdc950f0fc907ada5675b08ea5baab5d5834abfbf8c79b572f16f318a6cee489ef2a489beed0d0a7ef415344986d92efd
如果您尝试在 Java 端解密此密文,您将收到发布的错误:IllegalBlockSizeException:数据不得超过 64 字节。
为什么C#代码会产生太长的密文?这是因为模数也有前导 0 字节,因此长度为 65 字节:
Base64: AJ+L/dVL9jnRX6IM87H8x2fR24t6wpzBDV7bcgPWblegR0LNK91z/OSX+lSLUgHSKJ9to/Eo8OMsREpNoJlEzI0= Hex: 009f8bfdd54bf639d15fa20cf3b1fcc767d1db8b7ac29cc10d5edb7203d66e57a04742cd2bdd73fce497fa548b5201d2289f6da3f128f0e32c444a4da09944cc8d
模数是用BigInteger.toByteArray()
(see
模数中的前导 0 字节导致由 C# 代码生成的密文,它也有前导 0 字节,因此 65 字节的长度无效。这没有多大意义,可能是一个错误。
要解决此问题,应为 C# 代码删除模数中的 0 字节,从而产生以下 Base64 编码模数(将产生 64 字节密文):
n4v91Uv2OdFfogzzsfzHZ9Hbi3rCnMENXttyA9ZuV6BHQs0r3XP85Jf6VItSAdIon22j8Sjw4yxESk2gmUTMjQ==
也可以去掉密文中的0字节,得到如下密文(Base64编码):
mKW3GprX/wdTbRdmUomwm9yVDw/JB62lZ1sI6luqtdWDSr+/jHm1cvFvMYps7kie8qSJvu0NCn70FTRJhtku/Q==
现在可以通过 Java 代码成功解密为明文(如果应用了一致的填充,请参阅 Michael Fehr 的
Davood