RSA加密:在android/java中加密,在python中解密(加密) 问题
我正在尝试在python和java/android之间配置非对称加密。用例是安全地存储用户密码(使用公钥),允许对服务器(具有私钥)进行重新身份验证 我已经在Python和Java中分别使用了加密算法,但无法让我的Python端对Java生成的密文进行解密。我认为两个最可能的问题是RSA加密:在android/java中加密,在python中解密(加密) 问题,java,android,python,encryption,rsa,Java,Android,Python,Encryption,Rsa,我正在尝试在python和java/android之间配置非对称加密。用例是安全地存储用户密码(使用公钥),允许对服务器(具有私钥)进行重新身份验证 我已经在Python和Java中分别使用了加密算法,但无法让我的Python端对Java生成的密文进行解密。我认为两个最可能的问题是 base64编码字符串的问题(一直在努力解决这些问题!),或者 客户端/服务器之间的填充和其他加密规范不匹配 为了在这里创建一个完整的示例,我将复制私钥和公钥,然后重新生成一个新的集以供实际使用 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;
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.backends import default_backendb
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导入
// 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;
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
)
)
使用相同的代码(以及另一个要加密的块),我可以在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.
这显然与java输出完全不同——尽管我不完全确定原因(或者这意味着什么!)
非常感谢任何帮助!感谢根据Kelakela的评论,我意识到问题在于Java代码的输出是Base64,而python代码需要二进制输入 解决方案非常简单:
from codecs import decode
ciphertext = base64.decode(java_out, 'base64')
然后以二进制格式对输出运行私钥.解密(密文…)
代码的其余部分对我来说很好。嗨,凯拉拉卡。你是对的,问题在于二进制和base64格式之间的差异——这不是我以前遇到过的。现在已经修复了,使用ciphertext=base64.decode(java_out,'base64')为Python代码创建新的输入。谢谢大家!@kelalaka您应该明确指出您所指的“消息”是纯文本加上填充。@kelalaka那么您的评论是误导性的,因为消息加上填充必须小于模数(不仅仅是消息)。@Kelalalaka-已经添加了一个答案来解释我所做的。再次感谢你。