杰瑞科技汇

Java、iOS、Android如何实现RSA加密互通?

Of course! This is a very common and important requirement for any developer working on a multi-platform application. Here’s a comprehensive guide on how to handle RSA key generation, encryption, and decryption between Java (backend), Android (client), and iOS (client).

The core principle is consistency. All platforms must use the same RSA standard, the same padding scheme, and the same encoding for the data.


The Core Concepts (The "Why")

Before diving into code, let's understand the critical settings that must be identical across all platforms.

1. Key Size

The most common size is 2048 bits. It's secure and widely supported. You can use 4096 for higher security, but it's slower and may have compatibility issues on very old devices. All platforms must use the same key size.

2. Padding Scheme

This is the most common point of failure. Padding schemes add random data to the message before encryption to make it a fixed block size and provide semantic security.

Java、iOS、Android如何实现RSA加密互通?-图1

  • OAEP (Optimal Asymmetric Encryption Padding): This is the modern, recommended standard. It's more secure than PKCS#1 v1.5. You should use this for all new development.
  • PKCS#1 v1.5: An older standard. While still widely supported, it's considered less secure than OAEP. You might need to use it for legacy systems.

All platforms must use the same padding scheme.

3. Hash Algorithm for OAEP

If you choose OAEP padding, you must also specify a hash algorithm to use with it.

  • SHA-256: The most common and recommended choice.
  • SHA-1: Older and less secure. Avoid if possible.

All platforms must use the same hash algorithm for OAEP.

4. Encoding

RSA works on bytes, not strings. You need to agree on an encoding format to convert your text (or any data) into bytes and back.

Java、iOS、Android如何实现RSA加密互通?-图2

  • Base64: The standard for representing binary data in an ASCII string. It's universally supported and safe for transmission in JSON, XML, or URLs. This is the recommended choice.
  • Hexadecimal: Another option, but Base64 is more compact and generally preferred.

All platforms must use the same encoding.


The Workflow: Key Generation & Distribution

  1. Generate Keys: Generate the RSA key pair once. The best place to do this is on your Java backend.
  2. Distribute Public Key: Send the public key to both your Android and iOS apps. This can be hardcoded in the app or fetched from a secure endpoint on first launch.
  3. Keep Private Key Secret: The private key must never leave your Java backend. It should be stored securely (e.g., in a keystore, environment variables, or a secure cloud key management service like AWS KMS or Google Cloud KMS).

Java (Backend) - Key Generation & Decryption

Java is the source of truth. We'll use the standard java.security package.

1. Key Generation (Java)

This is a one-time script to generate your keys.

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RsaKeyGenerator {
    public static void main(String[] args) throws Exception {
        // Use KeyPairGenerator to generate a 2048-bit RSA key pair
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048);
        KeyPair keyPair = generator.generateKeyPair();
        // Get the public and private keys
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        // Encode keys to Base64 strings for easy storage and distribution
        String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        System.out.println("-----BEGIN PUBLIC KEY-----");
        System.out.println(publicKeyStr);
        System.out.println("-----END PUBLIC KEY-----\n");
        System.out.println("-----BEGIN PRIVATE KEY-----");
        System.out.println(privateKeyStr);
        System.out.println("-----END PRIVATE KEY-----");
    }
}

2. Decryption (Java)

Your backend will receive encrypted data from the clients and decrypt it with the private key.

Java、iOS、Android如何实现RSA加密互通?-图3

import javax.crypto.Cipher;
import java.security.PrivateKey;
import java.util.Base64;
public class RsaDecryptor {
    // The private key string generated earlier
    private static final String PRIVATE_KEY_STR = "YOUR_BASE64_ENCODED_PRIVATE_KEY_HERE";
    public static void main(String[] args) throws Exception {
        // 1. Load the Private Key from the Base64 string
        PrivateKey privateKey = getPrivateKey(PRIVATE_KEY_STR);
        // 2. The encrypted data received from the client (Base64 string)
        String encryptedDataB64 = "CLIENT_SENT_ENCRYPTED_BASE64_STRING";
        // 3. Decrypt the data
        String decryptedData = decrypt(encryptedDataB64, privateKey);
        System.out.println("Decrypted Data: " + decryptedData);
    }
    public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception {
        byte[] decodedKey = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }
    public static String decrypt(String encryptedDataB64, PrivateKey privateKey) throws Exception {
        // Use RSA/ECB/OAEPWithSHA-256AndMGF1Padding for modern security
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // Decode the Base64 encrypted data to bytes
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedDataB64);
        // Decrypt
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        // Convert bytes back to a string (assuming the original data was text)
        return new String(decryptedBytes, "UTF-8");
    }
}

Android (Client) - Encryption

Android uses the same java.security package, so the code is very similar to the Java backend.

1. Encryption (Android)

Add the public key (generated in Java) to your Android app as a constant string.

// In your Android Activity, Service, or ViewModel
import android.util.Base64; // Note: Use Android's Base64, not java.util.Base64 for older APIs
import javax.crypto.Cipher;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
public class AndroidRsaEncryptor {
    // The public key string from your Java backend
    private static final String PUBLIC_KEY_STR = "YOUR_BASE64_ENCODED_PUBLIC_KEY_HERE";
    public static String encrypt(String dataToEncrypt) throws Exception {
        // 1. Load the Public Key from the Base64 string
        PublicKey publicKey = getPublicKey(PUBLIC_KEY_STR);
        // 2. Encrypt the data
        return encrypt(dataToEncrypt, publicKey);
    }
    public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
        // Use Android's Base64 class for compatibility
        byte[] decodedKey = Base64.decode(publicKeyStr, Base64.DEFAULT);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        // IMPORTANT: Use the same transformation as the Java decryptor
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] dataToEncrypt = data.getBytes("UTF-8");
        // RSA can only encrypt a small amount of data (key size / 8 - padding overhead)
        // For a 2048-bit key, this is around 190 bytes. For longer data, you must use a hybrid approach.
        byte[] encryptedBytes = cipher.doFinal(dataToEncrypt);
        // Encode the encrypted bytes to a Base64 string for easy transport
        return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP);
    }
}

Usage:

try {
    String sensitiveData = "My secret password";
    String encryptedData = AndroidRsaEncryptor.encrypt(sensitiveData);
    // Send 'encryptedData' to your Java backend
} catch (Exception e) {
    e.printStackTrace();
}

iOS (Client) - Encryption

iOS uses the CryptoKit framework (recommended for iOS 13+) or the CommonCrypto library (for older versions).

1. Encryption (iOS with CryptoKit)

This is the modern and preferred way.

import CryptoKit
import Foundation
struct RsaEncryptor {
    // The public key string from your Java backend
    static let publicKeyStr = "YOUR_BASE64_ENCODE

分享:
扫描分享到社交APP
上一篇
下一篇