2012-09-18 73 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; 
    }