gpt4 book ai didi

java - 非对称加密差异 - Android 与 Java

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:09:48 25 4
gpt4 key购买 nike

我最近开始编写我用 Java 编写的在线游戏的 Android 版本。但是,我遇到了与加密不一致的问题。 Java 应用程序工作正常 - 它从文件中读取公钥,加密一些文本并将其传递到服务器,在服务器上使用私钥正确解密。在 android 上,一切似乎都正常(并且正在运行相同的代码),但是服务器有一个 BadPaddingException 试图解密消息。我在下面包含了所有相关代码和事件的逐步顺序:

连接到服务器后发生的第一件事是对称 key 的协议(protocol)。这是在客户端生成的,因此:

SecretKey symmetricKey = null;
try
{
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
symmetricKey = keyGen.generateKey();
}
catch (Throwable t)
{
Debug.stackTrace(t, "Failed to generate symmetric key.");
}

return symmetricKey;

然后将其转换为 Base64 字符串:

byte[] keyBytes = secretKey.getEncoded();
return base64Interface.encode(keyBytes);

并使用公钥加密:

public static String encrypt(String messageString, Key key)
{
String encryptedString = null;
try
{
byte[] messageBytes = messageString.getBytes();
String algorithm = key.getAlgorithm()
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherData = cipher.doFinal(messageBytes);
encryptedString = base64Interface.encode(cipherData);

//Strip out any newline characters
encryptedString = encryptedString.replaceAll("\n", "");
encryptedString = encryptedString.replaceAll("\r", "");
}
catch (Throwable t)
{
Debug.append("Caught " + t + " trying to encrypt message: " + messageString);
}

return encryptedString;
}

以这种形式传递给服务器,服务器使用私钥解密消息并恢复SecretKey对象:

public static String decrypt(String encryptedMessage, Key key)
{
String messageString = null;
try
{
byte[] cipherData = base64Interface.decode(encryptedMessage);
String algorithm = key.getAlgorithm();
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] messageBytes = cipher.doFinal(cipherData);
messageString = new String(messageBytes);
}
catch (Throwable t)
{
Debug.append("Caught " + t + " trying to decrypt message: " + encryptedMessage, failedDecryptionLogging);
}

return messageString;
}

但是,每当我对从 Android 应用传递过来的消息执行此操作时,doFinal 行都会产生以下异常:

11/07 12:55:55.975   javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(Unknown Source)
at sun.security.rsa.RSAPadding.unpad(Unknown Source)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:354)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:380)
at javax.crypto.Cipher.doFinal(Cipher.java:2121)
at util.EncryptionUtil.decrypt(EncryptionUtil.java:85)
at server.MessageHandlerRunnable.handleUnencryptedMessage(MessageHandlerRunnable.java:226)
at server.MessageHandlerRunnable.getResponse(MessageHandlerRunnable.java:188)
at server.MessageHandlerRunnable.run(MessageHandlerRunnable.java:85)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

我的第一个想法是,问题必须出在 Base64 编码/解码中,因为这是 Android 和桌面版本之间唯一不同的代码。但是,我做了一些测试并验证了这些是一致的,并且我的服务器代码可以使用任何一种编码方法恢复原始文本。

我的下一个想法是,Android 版本一定是使用了错误的公钥。这是在启动时使用以下代码从两个平台通用的文件生成的:

public static void generatePublicKey()
{
InputStream in = null;
ObjectInputStream oin = null;

try
{
in = KeyGeneratorUtil.class.getResourceAsStream("/assets/public.key");
oin = new ObjectInputStream(new BufferedInputStream(in));

BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
MessageUtil.publicKey = fact.generatePublic(keySpec);
}
catch (Throwable e)
{
Debug.stackTrace(e, "Unable to read public key - won't be able to communicate with Server.");
}
finally
{
if (in != null)
{
try {in.close();} catch (Throwable t) {}
}

if (oin != null)
{
try {oin.close();} catch (Throwable t) {}
}
}
}

当我查看两个平台上的 key 时(使用 toString()),我看到以下内容(我截断了模数):

桌面:

Sun RSA 公钥,1024 位模数:11920225567195913955197820411061866681846853580...公共(public)指数:65537

安卓:

OpenSSLRSAPublicKey{modulus=a9bfe8d8a199fc6a...,publicExponent=10001}

乍一看它们似乎完全不同,但我现在确信它们等同于一个以十进制表示的(桌面)和另一个以十六进制表示的(Android)。十六进制的 10001 相当于十进制的 65537,将十六进制模数放入在线转换器会生成一个至少以十进制模数的正确数字开头的数字。那么,为什么我会看到 BadPaddingException?

最后一件值得注意的事情,这似乎与大约一年前在这个问题中提出的问题相同:

RSA on Android is different from PC

但是,没有提出任何解决方案,我认为值得提出一个新问题,我可以在其中提供我可用的所有信息。

最佳答案

BadPaddingException s 通常由以下原因之一引起:

  1. 传递给解密函数的密文不等于从加密函数接收到的密文(仅仅一个位的差异就会完全破坏这个过程)。

  2. 使用不同的 key (或不匹配的私钥)解密数据。

  3. 该程序尝试取消填充用方案 A 填充的消息使用方案 B .

既然您已经验证了 1. 和 2. 是正确的,那么 3. 很可能是您问题的根源。

您在两端使用相同编程语言的相同代码,那么为什么会有任何不兼容?罪魁祸首是以下两行代码:

String algorithm = key.getAlgorithm();
Cipher cipher = Cipher.getInstance(algorithm);

由于 key 可以与任何填充方案结合使用,它只保存它所针对的算法,其效果是 key.getAlgorithm()返回 "RSA" .打电话Cipher.getInstance("RSA")这通常不是一个好主意,因为 Java 会自动为 cipher-modepadding 选择platform dependent 默认值。

这可以通过传递完整的密码字符串 ( "<algorithm>/<mode>/<padding>" ) 来避免,例如 "RSA/ECB/PKCS1Padding" .为所有人执行此操作总是一个好主意 Cipher使用 JCE 库时的实例。

关于java - 非对称加密差异 - Android 与 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31359694/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com