2017-02-15 40 views
2

逗人,Android上进行加密RSA InvalidKeyException将

我需要帮助理解为什么decryptString不工作,并抛出“java.security.InvalidKeyException:需要RSA私钥或公钥”。当调用加密方法时,我使用公钥通过私钥/证书。

感谢您的帮助!

public class KeysHandler { 

    /*** 
    * Generate and store in AndroidKeyStore a security KeyPair keys. 
    * @param alias - Alias to create the key. 
    * @return KeyPair object with: private and public key. 
    */ 
    public static KeyPair generateKeyPair(String alias) { 
     KeyPair kp = null; 
     if (alias != null) { 
      try { 

       KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); 
       kpg.initialize(new KeyGenParameterSpec.Builder(alias, 
         KeyProperties.PURPOSE_SIGN | 
         KeyProperties.PURPOSE_VERIFY | 
         KeyProperties.PURPOSE_ENCRYPT | 
         KeyProperties.PURPOSE_DECRYPT) 
         .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) 
         .build()); 

       kp = kpg.generateKeyPair(); 

      } catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException ex) { 
       kp = null; 
      } 
     } 
     return kp; 
    } 

    public static String encryptString(String alias, String textToEncrypt) { 
     String cipheredText = null; 

     try { 
      KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 
      keyStore.load(null); 

      KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null); 

      // Encrypt the text 
      if(textToEncrypt != null && textToEncrypt.length() > 0) { 

       Cipher input = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); 
       input.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey()); 

       ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
       CipherOutputStream cipherOutputStream = new CipherOutputStream(
         outputStream, input); 
       cipherOutputStream.write(textToEncrypt.getBytes("UTF-8")); 
       cipherOutputStream.close(); 

       byte[] vals = outputStream.toByteArray(); 
       cipheredText = Base64.encodeToString(vals, Base64.DEFAULT); 
      } 
     } catch (Exception e) { 
      cipheredText = null; 
     } 

     return cipheredText; 
    } 


    public static String decryptString(String alias, String cipheredText) { 

     String clearText = null; 
     try { 
      KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 
      keyStore.load(null); 

      KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null); 

      Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); 
      output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey()); 

      CipherInputStream cipherInputStream = new CipherInputStream(
        new ByteArrayInputStream(Base64.decode(cipheredText, Base64.DEFAULT)), output); 
      ArrayList<Byte> values = new ArrayList<>(); 
      int nextByte; 
      while ((nextByte = cipherInputStream.read()) != -1) { 
       values.add((byte)nextByte); 
      } 

      byte[] bytes = new byte[values.size()]; 
      for(int i = 0; i < bytes.length; i++) { 
       bytes[i] = values.get(i).byteValue(); 
      } 

      clearText = new String(bytes, 0, bytes.length, "UTF-8"); 

     } catch (Exception e) { 
      clearText = null; 
     } 

     return clearText; 
    } 
} 

回答

3

您忽略了密码提供:

Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 

其次,你可以先实例化供应商,以确保这样的作品,然后沿着将它作为第二个参数Cipher.getInstance().第二个参数可以是一个字符串(提供者名称)或提供者(对象)。使用第二个可能会使调试更容易。

+1

@FrederikHV真的很感谢,它省略了“AndroidOpenSSL”,就像一个魅力。祝你有个愉快的一周! – Mateus

+0

你忽略了哪里?在加密和解密这两个地方都省略了?谢谢。 – sandeepmaaram

+1

@sandeepmaaram无论你在哪里调用Cipher.getInstance – FrederikVH