java - RSA加密: Encrypt in android/java,在python中解密(密码学)

标签 java android python encryption rsa

问题

我正在尝试在 python 和 java/android 之间配置非对称加密。用例是安全地存储用户密码(使用公钥),启用对服务器(具有私钥)的重新身份验证。

我的加密算法在 Python 和 Java 中分别运行,但无法让我的 Python 端解密在 Java 中生成的密文。我认为两个最有可能的问题是

  1. base64 编码字符串的问题(一直在努力解决这些问题!),或者
  2. 客户端/服务器之间的填充和其他加密规范不匹配

为了在这里创建一个完整的示例,我将复制私钥和公钥,然后重新生成一个新的集合以供实际使用。

Java(客户端)端代码:

Java 导入

// Java imports
import android.util.Base64;
import android.util.Log;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;

Java 加密代码 - 我为代码格式/宽度道歉...

public class RSAEncryption {

    public void encrypt (String ... strings) throws Exception {

        // Load in public key, remove escape characters, headers, footers:     
        String public_key_string = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6kTFJl+6jG2rfYlZxtFi\nzajOgvKgInJHOa4i3G5vB9c7f7kzsTMOmeg5YHn3LNndg4Wx4AyfN5fbcNGg+KmJ\nK91b2lkgFy7pVEhWfzK4/yqk0liG7MwuN0G8GqUjIqJOXPS6lXB9Zr3n9QyTkKGV\n9cnNVPV1CNuN3bOu0t8Mu3fvZ+z8edq/cfUpTXwDdfRmZ6WeWxxqogK2uCwmneEN\n8kqyWE4OxhyqLJMw9mCGHOqTVgJUnvjMBezywr6s3vIcs2Q7CnxQx/g/GTqhUxLS\nHDlyAFDbhU4BWkCHrCa/nTyIFgXC9X4YRpQd24xfGXJjB2qUVv2H0O5FoRJAEYvS\nfQIDAQAB\n-----END PUBLIC KEY-----\n";

        String publicKeyContent = public_key_string.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");

        // Encrypt input using OAEP / SHA-256 /MGF1
        byte[] input = strings[0].getBytes();
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding");

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        byte[] publicBytes = Base64.decode(publicKeyContent, Base64.DEFAULT);
        X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(publicBytes);
        PublicKey pubKey = keyFactory.generatePublic(keySpecX509);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey, new OAEPParameterSpec("SHA-256",
                "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
        byte[] cipherText = cipher.doFinal(input);

        return cipherText;

    }

}

如果我使用输入字符串 = "test text"运行这些代码,我会得到加密输出:

BoOymgUGnB/LIqYOhBmW60HCL4s6FQFlNpRmhqm63AGq7gud4g96og6f+5yHUVHktAT0pl93UpAz//aae4esTseR6/o7jD/NGS+gZlNRHsSuNNstVZ8wOp1S03YcHYEpXtTdElMiKso4cbZmO20SoUvyzjI5e7RM1aWKCebqCvG7RYneCgoMi611AY2cVSwMYOENcRwqXeB3sFMrjoNQ1TkkgHU5MSxDbVLbNO72AYYQi/TkwiQ57qnjgk3KHXeatJv/5hWqa5ooBCy6aLDFux6X2721wTVa2/RSiZKG7DJHObV5pQNw4zjGWc4d5IJ+P/o6GKHY4fTj8ujqS6A44Q==

我相信这是可行的,因为我可以使用私钥(使用另一个代码块,此处未复制)成功解密它。

然后将其用作 python 代码的输入。

Python(服务器端)代码

Python 导入

from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.backends import default_backendb

Python解密代码

PRIVATE_KEY_STRING='-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDqRMUmX7qMbat9\niVnG0WLNqM6C8qAickc5riLcbm8H1zt/uTOxMw6Z6Dlgefcs2d2DhbHgDJ83l9tw\n0aD4qYkr3VvaWSAXLulUSFZ/Mrj/KqTSWIbszC43QbwapSMiok5c9LqVcH1mvef1\nDJOQoZX1yc1U9XUI243ds67S3wy7d+9n7Px52r9x9SlNfAN19GZnpZ5bHGqiAra4\nLCad4Q3ySrJYTg7GHKoskzD2YIYc6pNWAlSe+MwF7PLCvqze8hyzZDsKfFDH+D8Z\nOqFTEtIcOXIAUNuFTgFaQIesJr+dPIgWBcL1fhhGlB3bjF8ZcmMHapRW/YfQ7kWh\nEkARi9J9AgMBAAECggEARuUi6JcFxGOYBzies51AEk7omBZGwcXlqh35rM26yhun\nhOKOMyzpWUg+vOSMGcWg1KGMD+qh8FgDb6Pw2++qdFzb5DsejAWFVR1DF+FIvOex\n03o48sZjohNBkqqw9FU788OYB4twV7xWywDQU2+jCyvT+McDcPfIefRbjrMzjjOM\nOhMY0F6OXeDpuZttgqZsP65aA7yaIfjuk5tuYbpZvNmV1DAlqfGmxt2PO1laobGQ\nS7Vx18zpWWdh/GgnbZDD3SG69AmAWIdOZNV6SuUC5lgOqw2O+8TB7MXFbiCy7v5J\n1tMap6OCRDm5jLsc6ZFP5Zs1s9/FnW9/jCxw4kFxPQKBgQD7DcVUaW7rKUmYORAA\nqY6uAIu+Lo+607G4Nva52Rotj0vdiIsAYxJPP2dxKTjL0GLbKIsOcmd2xD0e1/yu\nlAu6koCyC5cT5XwNJ388XDwtWPU2J7mC1TKq0TJUZ56uzdZxNKOWQ7Upq3901zbQ\nQhssjJpgX09CPzlfpAc9NHhchwKBgQDu4lc5HaJNsFeEMOuaUmTUu+W+veIZZaV3\n7yTnLxoJCyqu5DVKvhMwDZP3I2JuvHbCPf3AzshvNcbCiG/6u9CQSbv4wRZO6p8c\nlIAymy0neaq7+uxHdvem58A4xIlKhlnNpzIqE9fay7ejAklGPTFs/YdsyVXwADVr\n30cfOdO92wKBgCCrGhJx5c0UAk+cnUh4x+g8ifKlfG6DPY0LGe/1IELtcqHRMsVK\nHwfQ6FUBWDKtWy/Jhs7KdEwwHQP2dxsAiMYuajDA8VfVdN8BVL02A16jRMVXRfyQ\nYZd4wWPaV/vHLTBt+RuEk/5oIp3Bo5BWCdMyOKRxwo6MS5r2bTq5qS/hAoGAKezT\nfhSzXYsrcOndD7KSO7vWcImG2wo55ji0c1aS7S9miFdI+xss5uwbIe614dV1ylVy\n6ZnhF5OKlK25aXn4+rnWIaxRq/wFfNCbR0ZwwFLcIi3BtjEs+cAGvm/P4KJ/tFY5\nuaTN53qFejh2f7tRp10/nVogmQSQW6ROKS7O+K0CgYA03s/ajxaYTLzBHpIdqisl\nsGaen4IBibB3OZs/vplBZ0xG34B8+MC8qgvC6DFVR4Y3XMol8lOGiS6OQVvIRjnC\nhqd/QobpH0j5Wy2cM+6yXVvj95dwif7QjaqDydniRhGbxa6iJ8vTYqyl9yNjWwX/\n72JRzDNB+9De2LntVwzBwA==\n-----END PRIVATE KEY-----\n'

#Load the java output into a bytes object to decrypt
java_out = b'BoOymgUGnB/LIqYOhBmW60HCL4s6FQFlNpRmhqm63AGq7gud4g96og6f+5yHUVHktAT0pl93UpAz//aae4esTseR6/o7jD/NGS+gZlNRHsSuNNstVZ8wOp1S03YcHYEpXtTdElMiKso4cbZmO20SoUvyzjI5e7RM1aWKCebqCvG7RYneCgoMi611AY2cVSwMYOENcRwqXeB3sFMrjoNQ1TkkgHU5MSxDbVLbNO72AYYQi/TkwiQ57qnjgk3KHXeatJv/5hWqa5ooBCy6aLDFux6X2721wTVa2/RSiZKG7DJHObV5pQNw4zjGWc4d5IJ+P/o6GKHY4fTj8ujqS6A44Q=='

#Load the private key string into a functioning key object
private_key = serialization.load_pem_private_key(
         PRIVATE_KEY_STRING.encode('UTF-8'),
         password=None,
         backend=default_backend()
         )

#Decrypt the input
private_key.decrypt(
    java_out,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

使用相同的代码(和另一个要加密的 block )我可以在 Python 中成功加密/解密。但是,当使用 Java 的输出作为输入时,此代码返回以下错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-71-9af0738427f1> in <module>()
      4         mgf=padding.MGF1(algorithm=hashes.SHA256()),
      5         algorithm=hashes.SHA256(),
----> 6         label=None
      7     )
      8 )

C:\ProgramData\OWTools\miniconda\lib\site-packages\cryptography\hazmat\backends\openssl\rsa.py in decrypt(self, ciphertext, padding)
    384         key_size_bytes = int(math.ceil(self.key_size / 8.0))
    385         if key_size_bytes != len(ciphertext):
--> 386             raise ValueError("Ciphertext length must be equal to key size.")
    387 
    388         return _enc_dec_rsa(self._backend, self, ciphertext, padding)

ValueError: Ciphertext length must be equal to key size.

一个可能有用的想法是,在要加密的python代码中,密文以以下格式输出:

b'N\xf2\xa7\xfaW6[Z\x0c\x14\xe7\xc8\xcb\xed\xa2xM\xea\x83\xa3\xb7\x05few!\x0e\\zd\xfe g\xbbO1\xfe\n\xa0Q\xab\xb8e0\xe9R^\xc8\xbbU\xfbuxp\x00\xf7>\xf8\x14\x1c\xd7\xca}\xd3\n{\xc9\xa2^\x8c0.\x9a\\\xe2\x89\xfd\xbf\xabw\x03\xc4\xdc\xfdX\xcf\xcc\x01\xc7\xc8\\j\xa9\xd7U\xfbP\xc2$\xd9^\x9e1\x9d&\xf1\x1b\x08%\xb3kF`\x19\xeb\xc8\xf0\x9f\xb1\x13\xaa\xa1\xed+X\xdc\x10!Fw\xae\x93\xb0\x80\xf3}\x98nz^\x04\xfe\x08T\x98d>[\xa7\x92\x08\x8a\r\xbc\x85\xf8\xcb\xce\xcc\x94\x95V\xf0\xad\x8d\x94N\x0c\x03\xf0\xbcT\x06%\x0b\x06\xcb_\xcauY$\n\xbc\xea\xde\xe4G\x05F\xf5\xef\x10\x83w"f5*&?\\9\x08\xd3}\xf0X\xb7\x06F\x99\xe1\xf3\x02\x14a\x7f\x1a0,?{\x12^|\xba\xed\xf6s\xed\xe6@m\xc7ex\x86\xf1\xae\xeec=\x92\x7fZ\x19\xee\x0f\x86\xb8\xf5T_\x9f\x1c'

这显然与 java 输出完全不同 - 虽然我不完全确定为什么(或那意味着什么!)

非常感谢任何帮助!谢谢

最佳答案

根据 Kelakela 的评论,我意识到问题是 Java 代码的输出是 Base64,而 python 代码需要二进制输入。

解决方案很简单:

from codecs import decode 
ciphertext = base64.decode(java_out, 'base64')

然后在二进制格式的输出上运行 private_key.decrypt(ciphertext, ... )

其余代码对我来说工作正常。

关于java - RSA加密: Encrypt in android/java,在python中解密(密码学),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54918139/

相关文章:

python - 为什么 len(a[0]) 与 a.shape[1] 不同

python - (重新)在 Python 中加权随机 CSV 样本

java - 如何确保长时间运行的 Java 线程永不消亡

java - 从android中listAdapter之外的viewList访问 View 项

android - 在适配器中获取 ArrayIndexOutOfBoundsException

java - 最后一个已知位置是在多长时间前记录的?

android - 带有底部粘性按钮的 BottomSheetDialogFragment

python - 我得到高斯图像的黑色拉普拉斯图像

java - 为什么这个 java 输入验证循环不起作用

java - 将数据从一个类传递到另一个类