将Python pyCrypto PKCS1 OAEP解密逻辑转换为Java Cipher实现
Got it, let's walk through translating that PyCrypto PKCS1_OAEP decryption logic to Android Java step by step. I've dealt with this exact cross-language crypto mismatch a few times, so here's what you need to get right:
First, Understand the Python Baseline
Your Python code is likely doing something like this (based on PKCS1_OAEP.new):
from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA # Load RSA private key private_key = RSA.import_key(open("private_key.pem").read()) # Initialize OAEP decryptor (defaults: SHA-1 for hash + MGF1, empty PSource) cipher = PKCS1_OAEP.new(private_key) # Decrypt ciphertext bytes decrypted_data = cipher.decrypt(encrypted_bytes)
We need to mirror these exact defaults in Java—any parameter mismatch will cause decryption to fail silently or throw errors.
Step 1: Load Your RSA Private Key in Android
First, handle loading your private key. If you're using a PEM-formatted key (like the one in Python), clean up the headers and decode from Base64:
import android.util.Base64; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; // Example PEM private key string String privateKeyPem = "-----BEGIN RSA PRIVATE KEY-----\n" + "YOUR_KEY_CONTENTS_HERE\n" + "-----END RSA PRIVATE KEY-----"; // Strip PEM headers and whitespace String cleanedPem = privateKeyPem.replace("-----BEGIN RSA PRIVATE KEY-----", "") .replace("-----END RSA PRIVATE KEY-----", "") .replaceAll("\\s", ""); // Decode Base64 to raw key bytes byte[] privateKeyBytes = Base64.decode(cleanedPem, Base64.DEFAULT); // Generate PrivateKey object (works for PKCS#8 formatted keys) PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Note: If your key is in PKCS#1 format (common in PyCrypto), convert it to PKCS#8 first, or use the BouncyCastle provider to load PKCS#1 directly (more on that later).
Step 2: Configure Cipher for OAEP Decryption
Mirror PyCrypto's OAEP parameters exactly in Java:
import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSource; import java.security.spec.MGF1ParameterSpec; import java.nio.charset.StandardCharsets; // Define OAEP params to match PyCrypto's defaults OAEPParameterSpec oaepParams = new OAEPParameterSpec( "SHA-1", // Main hash algorithm "MGF1", // Mask generation function MGF1ParameterSpec.SHA1, // MGF1 hash algorithm (matches main hash) PSource.PSpecified.DEFAULT // Empty PSource (PyCrypto's default) ); // Get cipher instance with correct algorithm string Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); // Initialize for decryption with private key + OAEP params cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams); // Decrypt your ciphertext (replace encryptedBytes with your actual byte array) byte[] decryptedBytes = cipher.doFinal(encryptedBytes); // Convert to string if needed (adjust charset to match your data) String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
Step 3: Handle Non-Default Configurations
If your Python code uses a different hash (e.g., SHA-256), update the parameters accordingly:
- Swap
"SHA-1"with"SHA-256"inOAEPParameterSpec - Use
MGF1ParameterSpec.SHA256instead ofSHA1 - Update the cipher algorithm string to
"RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
Step 4: Fix Provider Compatibility Issues
If you hit NoSuchAlgorithmException, use the BouncyCastle provider (it's more flexible for RSA OAEP variants):
- Add it to your app's
build.gradle:
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
- Register the provider before using the cipher:
import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; // Add this once (e.g., in your Application class) Security.addProvider(new BouncyCastleProvider()); // Get cipher with BouncyCastle provider Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", "BC");
Critical Tips to Avoid Failure
- Parameter Exactness: The hash, MGF1 hash, and PSource must match between Python and Java. Even a tiny difference (SHA-1 vs SHA-256) will break decryption.
- Key Formats: PyCrypto handles PKCS#1 and PKCS#8 keys seamlessly, but Java's default only supports PKCS#8. Convert PKCS#1 keys or use BouncyCastle.
- Byte Consistency: Ensure the ciphertext byte array is passed correctly (no accidental encoding mismatches between Python and Java).
内容的提问来源于stack exchange,提问作者Ersen Osman

