2012-09-18 108 views
28

我正在爲Android中的RSA加密和解密實施演示。我可以很好地執行加密,但在解密中,我得到一個例外:>>java.security.InvalidKeyException: unknown key type passed to RSAAndroid中的RSA加密解密

KeyPairGenerator kpg; 
    KeyPair kp; 
    PublicKey publicKey; 
    PrivateKey privateKey; 
    byte [] encryptedBytes,decryptedBytes; 
    Cipher cipher,cipher1; 
    String encrypted,decrypted; 

    public String RSAEncrypt (final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
    { 
     kpg = KeyPairGenerator.getInstance("RSA"); 
     kpg.initialize(1024); 
     kp = kpg.genKeyPair(); 
     publicKey = kp.getPublic(); 
     privateKey = kp.getPrivate(); 

     cipher = Cipher.getInstance("RSA"); 
     cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
     encryptedBytes = cipher.doFinal(plain.getBytes()); 
     encrypted = new String(encryptedBytes); 
     System.out.println("EEncrypted?????"+encrypted); 
     return encrypted; 

    } 

    public String RSADecrypt (final String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
    { 

     cipher1=Cipher.getInstance("RSA"); 
     cipher1.init(Cipher.DECRYPT_MODE, privateKey); 
     decryptedBytes = cipher1.doFinal(result.getBytes()); 
     decrypted = new String(decryptedBytes); 
     System.out.println("DDecrypted?????"+decrypted); 
     return decrypted; 

    } 

而且我從這裏調用該函數:

encrypt.setOnClickListener(new OnClickListener() 
     { 
      public void onClick(View arg0) 
      { 
        try 
        { 
         RSAEncrypt rsaencrypt=new RSAEncrypt(); 
         rsaencrypt.RSAEncrypt(name); 

         result=rsaencrypt.RSAEncrypt(name); 
         Toast.makeText(getBaseContext(), result.toString(),Toast.LENGTH_SHORT).show(); 

         System.out.println("Result:"+result); 
        } 
        catch(Exception e) 
        { 
         e.printStackTrace(); 
         Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show(); 
        } 
      } 
     }); 

     decrypt.setOnClickListener(new OnClickListener() 
     { 
      public void onClick(View arg0) 
      { 
       { 
        try 
        { 
         RSAEncrypt rsadecrypt=new RSAEncrypt(); 

         rsadecrypt.RSADecrypt(result); 

         ans=rsadecrypt.RSADecrypt(result); 
         System.out.println("Result is"+ans); 
         Toast.makeText(getBaseContext(), ans.toString(),Toast.LENGTH_LONG).show(); 
        } 
        catch(Exception e) 
        { 
         e.printStackTrace(); 
         Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show(); 
         System.out.println("Exception is>>"+e); 
        } 
      } 
     }); 

回答

29

在RSA中,您應該使用公鑰加密和私鑰解密。

您的示例代碼用於加密和解密公鑰 - 這是行不通的。

因此,在解密部分,你應該初始化密碼是這樣的:

cipher1.init(Cipher.DECRYPT_MODE, privateKey); 

Furthermor代碼有第二顯著錯誤:

要轉換的字節數組與二進制內容爲String。

永遠不要將二進制數據轉換爲字符串!

字符串用於字符串字符而不是二進制數據。如果要將二進制數據打包爲字符串,請將其編碼爲可打印字符,例如使用十六進制或Base64。

以下示例使用來自org.apache.common.codec包的十六進制編碼器 - 必須安裝第三方庫。

public byte[] RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, 
     InvalidKeyException, IllegalBlockSizeException, BadPaddingException { 
    kpg = KeyPairGenerator.getInstance("RSA"); 
    kpg.initialize(1024); 
    kp = kpg.genKeyPair(); 
    publicKey = kp.getPublic(); 
    privateKey = kp.getPrivate(); 

    cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
    encryptedBytes = cipher.doFinal(plain.getBytes()); 
    System.out.println("EEncrypted?????" + org.apache.commons.codec.binary.Hex.encodeHexString(encryptedBytes)); 
    return encryptedBytes; 
} 

public String RSADecrypt(final byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, 
     InvalidKeyException, IllegalBlockSizeException, BadPaddingException { 

    cipher1 = Cipher.getInstance("RSA"); 
    cipher1.init(Cipher.DECRYPT_MODE, privateKey); 
    decryptedBytes = cipher1.doFinal(encryptedBytes); 
    decrypted = new String(decryptedBytes); 
    System.out.println("DDecrypted?????" + decrypted); 
    return decrypted; 
} 
+0

非常感謝。你是對的..我做了錯誤在那..但現在我得到異常>> System.err(416):java.security.InvalidKeyException:未知的關鍵類型傳遞給RSA 請幫助我..謝謝提前.. –

+1

查看我的更新回答 – Robert

+2

感謝您的。只是一個評論:鍵是對稱的。因此,您可以使用public進行編碼,然後使用private進行解碼(確保向誰發送加密數據),或者使用private進行編碼,然後使用public進行解碼(以確保誰向您發送了加密數據)。做2(用2個不同的密鑰集),允許你執行'從誰'和'誰'安全方面。 – Pascal

1

我認爲問題是,你應該使用相同的密鑰對加密和解密的密碼。參考JavaDoc:

genKeyPair() This will generate a new key pair every time it is called. 
+0

@ jaredzhang..I編輯我code..but我得到同樣的Exception..Please評論我編輯的代碼.. –

+0

@ jaredzhang..I認爲你是right..But問題是,現在我獲取java.lang.NullPointerException .. –

+0

您的新代碼似乎不清楚,請確保您用於解密的私鑰與先前生成的私鑰相同。 – jaredzhang

0

當使用RSAEcvypt方法時,其填充PublicKey和私鑰。 而當你解密你生成的字節[]時,你的publicKey和privateKey是NULL。 因爲你得到這個錯誤。

你應該使用你的鑰匙static;

enter code here 

KeyPairGenerator kpg; 
KeyPair kp; 
static PublicKey publicKey; 
static PrivateKey privateKey; 
byte [] encryptedBytes,decryptedBytes; 
Cipher cipher,cipher1; 
String encrypted,decrypted; 
+0

這些是類屬性,因爲訪問這些鍵的方法不是靜態的,因此屬性不是靜態的。事實上,當您需要使用不同的數據值創建多個類的實例時,特別需要靜態屬性是一個非常糟糕的選擇。 – AaA

8

我的類:

package com.infovale.cripto; 

import java.io.UnsupportedEncodingException; 
import java.math.BigInteger; 
import java.security.InvalidKeyException; 
import java.security.KeyPair; 
import java.security.KeyPairGenerator; 
import java.security.NoSuchAlgorithmException; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.util.Arrays; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 

public class RSA { 

KeyPairGenerator kpg; 
KeyPair kp; 
PublicKey publicKey; 
PrivateKey privateKey; 
byte[] encryptedBytes, decryptedBytes; 
Cipher cipher, cipher1; 
String encrypted, decrypted; 

public String Encrypt (String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
{ 
    kpg = KeyPairGenerator.getInstance("RSA"); 
    kpg.initialize(1024); 
    kp = kpg.genKeyPair(); 
    publicKey = kp.getPublic(); 
    privateKey = kp.getPrivate(); 

    cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
    encryptedBytes = cipher.doFinal(plain.getBytes()); 

    encrypted = bytesToString(encryptedBytes); 
    return encrypted; 

} 

public String Decrypt (String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException 
{   

    cipher1=Cipher.getInstance("RSA"); 
    cipher1.init(Cipher.DECRYPT_MODE, privateKey); 
    decryptedBytes = cipher1.doFinal(stringToBytes(result)); 
    decrypted = new String(decryptedBytes); 
    return decrypted; 

} 

public String bytesToString(byte[] b) { 
    byte[] b2 = new byte[b.length + 1]; 
    b2[0] = 1; 
    System.arraycopy(b, 0, b2, 1, b.length); 
    return new BigInteger(b2).toString(36); 
} 

public byte[] stringToBytes(String s) { 
    byte[] b2 = new BigInteger(s, 36).toByteArray(); 
    return Arrays.copyOfRange(b2, 1, b2.length); 
} 
} 
2

這裏是Android的一個例子:

  • 產生專用/公共密鑰對
  • 加密字符串
  • 解密加密字符串

這些方法處理所有base 64編碼/解碼。

public void TestEncryptData(String dataToEncrypt) { 
     // generate a new public/private key pair to test with (note. you should only do this once and keep them!) 
     KeyPair kp = getKeyPair(); 

     PublicKey publicKey = kp.getPublic(); 
     byte[] publicKeyBytes = publicKey.getEncoded(); 
     String publicKeyBytesBase64 = new String(Base64.encode(publicKeyBytes, Base64.DEFAULT)); 

     PrivateKey privateKey = kp.getPrivate(); 
     byte[] privateKeyBytes = privateKey.getEncoded(); 
     String privateKeyBytesBase64 = new String(Base64.encode(privateKeyBytes, Base64.DEFAULT)); 

     // test encryption 
     String encrypted = encryptRSAToString(dataToEncrypt, publicKeyBytesBase64); 

     // test decryption 
     String decrypted = decryptRSAToString(encrypted, privateKeyBytesBase64); 
    } 

    public static KeyPair getKeyPair() { 
     KeyPair kp = null; 
     try { 
      KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 
      kpg.initialize(2048); 
      kp = kpg.generateKeyPair(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return kp; 
    } 

    public static String encryptRSAToString(String clearText, String publicKey) { 
     String encryptedBase64 = ""; 
     try { 
      KeyFactory keyFac = KeyFactory.getInstance("RSA"); 
      KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKey.trim().getBytes(), Base64.DEFAULT)); 
      Key key = keyFac.generatePublic(keySpec); 

      // get an RSA cipher object and print the provider 
      final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING"); 
      // encrypt the plain text using the public key 
      cipher.init(Cipher.ENCRYPT_MODE, key); 

      byte[] encryptedBytes = cipher.doFinal(clearText.getBytes("UTF-8")); 
      encryptedBase64 = new String(Base64.encode(encryptedBytes, Base64.DEFAULT)); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return encryptedBase64.replaceAll("(\\r|\\n)", ""); 
    } 

    public static String decryptRSAToString(String encryptedBase64, String privateKey) { 

     String decryptedString = ""; 
     try { 
      KeyFactory keyFac = KeyFactory.getInstance("RSA"); 
      KeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey.trim().getBytes(), Base64.DEFAULT)); 
      Key key = keyFac.generatePrivate(keySpec); 

      // get an RSA cipher object and print the provider 
      final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING"); 
      // encrypt the plain text using the public key 
      cipher.init(Cipher.DECRYPT_MODE, key); 

      byte[] encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT); 
      byte[] decryptedBytes = cipher.doFinal(encryptedBytes); 
      decryptedString = new String(decryptedBytes); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return decryptedString; 
    }