4

我想在Android中端的数据进行加密,并在PHP侧 解密我使用phpseclib在PHP中生成公钥/私钥公共/私有密钥加密Android的PHP

我生成后键此公钥我得到了PHP端

-----BEGIN RSA PUBLIC KEY-----". 
      "MIGJAoGBAKks62Itns2uU/dVZJ4kCkMinHgyeh/rdMD53a4Zu2a76OIJvdSZ8q4c". 
      "YTWvPj0giefVtMc7tV4c6AAw04jyIfmCTvcQUlHI+sspHxXDlQTagNoxCuA29b5L". 
      "9MKO6Ok0LwF9rGgTywC1heNEulZz9ISn9FQDazJT+Bd9cnNOrJRdAgMBAAE=". 
      "-----END RSA PUBLIC KEY----- 

,然后我把它编码为Base64和得到这个base64编码的关键

LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tTUlHSkFvR0JBS2tzNjJJdG5zMnVVL2RWWko0a0NrTWluSGd5ZWgvcmRNRDUzYTRadTJhNzZPSUp2ZFNaOHE0Y1lUV3ZQajBnaWVmVnRNYzd0VjRjNkFBdzA0anlJZm1DVHZjUVVsSEkrc3NwSHhYRGxRVGFnTm94Q3VBMjliNUw5TUtPNk9rMEx3RjlyR2dUeXdDMWhlTkV1bFp6OUlTbjlGUURhekpUK0JkOWNuTk9ySlJkQWdNQkFBRT0tLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0t 

我把它复制到Android端使用它来加密数据,但我得到InvalidKeySpecException

的Android端代码:

public static byte[] encrypt(String text) { 

     byte[] encodedPublicKey= Base64.decode("LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tTUlHSkFvR0JBS2tzNjJJdG5zMnVVL2RWWko0a0NrTWluSGd5ZWgvcmRNRDUzYTRadTJhNzZPSUp2ZFNaOHE0Y1lUV3ZQajBnaWVmVnRNYzd0VjRjNkFBdzA0anlJZm1DVHZjUVVsSEkrc3NwSHhYRGxRVGFnTm94Q3VBMjliNUw5TUtPNk9rMEx3RjlyR2dUeXdDMWhlTkV1bFp6OUlTbjlGUURhekpUK0JkOWNuTk9ySlJkQWdNQkFBRT0tLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0t", Base64.DEFAULT); 



    PublicKey publicKey=null; 
    KeyFactory keyFactory = null; 
    try { 
     keyFactory = KeyFactory.getInstance("RSA"); 
     X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey); 
     publicKey = keyFactory.generatePublic(publicKeySpec); 

    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    }catch (InvalidKeySpecException e) { 
     e.printStackTrace(); 
    } 


    byte[] cipherText = null; 
    try { 
     // get an RSA cipher object and print the provider 
     final Cipher cipher = Cipher.getInstance("RSA"); 
     // encrypt the plain text using the public key 
     cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
     cipherText = cipher.doFinal(text.getBytes()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return cipherText; 
} 
+2

按照[文档](http://docs.oracle.com/javase/7/docs/api/java/security/spec/X509EncodedKeySpec.html),X509EncodedKeySpec期望一个ASN.1格式的键,而您传递的是[PEM](https://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail)格式的密钥。 – adelphus

+1

heh,双base64编码。这真的没有道理。你需要base64将二进制转换为文本;如果输入*已经是文本*,base64几乎没有用处,你不同意吗?剥去页眉和页脚,看看是否有效。 –

+1

@MaartenBodewes:它不起作用,因为格式是更简单的PKCS#1公钥,只是模数和指数。 Java期望更复杂的SubjectPublicKeyInfo野兽,也就是Java-ese中的“X509EncodedKey”。 –

回答

1

下面的代码解析PEM,将其送至PKCS#1 RSAPublicKey来自BouncyCastle的类解析器,然后从模数和指数构造JCE RSAPublicKey。其余的是错误处理,关键本身以及显示它的主要方法。

对于Android,您可能需要使用Spongy Castle。

package nl.owlstead.stackoverflow; 

import java.io.IOException; 
import java.io.StringReader; 
import java.security.KeyFactory; 
import java.security.NoSuchAlgorithmException; 
import java.security.interfaces.RSAPublicKey; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.RSAPublicKeySpec; 

import org.bouncycastle.util.io.pem.PemObject; 
import org.bouncycastle.util.io.pem.PemReader; 

public final class RSAPublicKeyFromOpenSSL_PKCS1_PEM { 
    private static final String PEM = "-----BEGIN RSA PUBLIC KEY-----\r\n" 
      + "MIGJAoGBAKks62Itns2uU/dVZJ4kCkMinHgyeh/rdMD53a4Zu2a76OIJvdSZ8q4c\r\n" 
      + "YTWvPj0giefVtMc7tV4c6AAw04jyIfmCTvcQUlHI+sspHxXDlQTagNoxCuA29b5L\r\n" 
      + "9MKO6Ok0LwF9rGgTywC1heNEulZz9ISn9FQDazJT+Bd9cnNOrJRdAgMBAAE=\r\n" 
      + "-----END RSA PUBLIC KEY-----\r\n"; 

    public static RSAPublicKey parsePEM(final String pem) 
      throws IllegalArgumentException { 

     // --- read PEM object 
     final PemObject readPemObject; 
     try (final PemReader reader = new PemReader(new StringReader(PEM))) { 
      readPemObject = reader.readPemObject(); 
     } catch (final IOException e) { 
      throw new IllegalArgumentException("Not a PEM object", e); 
     } 
     if (!readPemObject.getType().equalsIgnoreCase("RSA PUBLIC KEY")) { 
      throw new IllegalArgumentException("Not a public key"); 
     } 
     final byte[] pemContent = readPemObject.getContent(); 

     // --- create Bouncy Castle PKCS#1 public key 
     final org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey; 
     try { 
      pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey 
        .getInstance(pemContent); 
     } catch (final Exception e) { 
      throw new IllegalArgumentException(
        "Could not parse BER PKCS#1 public key structure", e); 
     } 

     // --- convert to JCE RSAPublicKey 
     final RSAPublicKeySpec spec = new RSAPublicKeySpec(
       pkcs1PublicKey.getModulus(), pkcs1PublicKey.getPublicExponent()); 
     final KeyFactory rsaKeyFact; 
     try { 
      rsaKeyFact = KeyFactory.getInstance("RSA"); 
     } catch (final NoSuchAlgorithmException e) { 
      throw new IllegalStateException("RSA KeyFactory should be available", e); 
     } 
     try { 
      return (RSAPublicKey) rsaKeyFact.generatePublic(spec); 
     } catch (InvalidKeySpecException e) { 
      throw new IllegalArgumentException(
        "Invalid RSA public key, modulus and/or exponent invalid", e); 
     } 
    } 

    public static void main(final String ... args) throws Exception { 
     final RSAPublicKey publicKey = parsePEM(PEM); 
     System.out.println(publicKey); 
    } 
} 
+0

你也前缀正确DER结构的公钥来创建一个'SubjectPublicKey'和分析,使用'X509PublicKeySpec',但只有在您事先知道确切的密钥大小时才有效,所以它比这更脆弱。 –

+0

这是否回答你的问题,Khaled? –