2012-04-19 87 views
4

我想加密和解密使用RSA算法的字符串。這裏的加密工作正常,但問題在於解密。 代碼在DECRYPT方法中達到doFinal時終止。 我輸入錯誤或公鑰和私鑰有問題嗎? 請給我關於這方面的建議。 謝謝你。需要幫助在RSA加密(doFinal)

public class rsa 
{ 
private KeyPair keypair;  

public rsa() throws NoSuchAlgorithmException, NoSuchProviderException 
    { 
     KeyPairGenerator keygenerator = KeyPairGenerator.getInstance("RSA"); 
     SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); 
     keygenerator.initialize(1024, random); 
     keypair = keygenerator.generateKeyPair(); 
    } 
public String ENCRYPT(String Algorithm, String Data) throws Exception 
{ 
    String alg = Algorithm; 
    String data=Data; 
    byte[] encrypted=new byte[2048]; 
    if(alg.equals("RSA")) 
    { 

     PublicKey publicKey = keypair.getPublic(); 
     Cipher cipher; 
     cipher = Cipher.getInstance("RSA"); 
     cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
     encrypted = cipher.doFinal(data.getBytes()); 
     System.out.println("Encrypted String[RSA] -> " + encrypted); 
    } 
    return encrypted.toString(); 
} 
public String DECRYPT(String Algorithm, String Data) throws Exception 
{ 
    String alg = Algorithm; 
    byte[] Decrypted=Data.getBytes(); 


    if(alg.equals("RSA")) 
    { 

     PrivateKey privateKey = keypair.getPrivate(); 
     Cipher cipher; 
     cipher = Cipher.getInstance("RSA"); 
     cipher.init(Cipher.DECRYPT_MODE, privateKey); 
     byte[] dec = cipher.doFinal(Decrypted); 

     System.out.println("Decrypted String[RSA] -> " + dec.toString()); 

    } 
    return Decrypted.toString(); 
} 
public static void main(String[] args) throws Exception 
{ 
    rsa RSA=new rsa(); 
    RSA.ENCRYPT("RSA", "avinash"); 
    RSA.DECRYPT("RSA","[[email protected]"); 
} 

}

got exception as 

Exception in thread "main" javax.crypto.BadPaddingException: Data must start with zero 
at sun.security.rsa.RSAPadding.unpadV15(Unknown Source) 
at sun.security.rsa.RSAPadding.unpad(Unknown Source) 
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:356) 
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:382) 
at javax.crypto.Cipher.doFinal(Cipher.java:2086) 
at EncryptionProvider.rsa.DECRYPT(rsa.java:56) 
at EncryptionProvider.rsa.main(rsa.java:68) 

加密的字符串[RSA] - > [B @ 4a96a

+0

獲取異常,因爲數據必須以零開頭。 – Avinash 2012-04-19 03:58:21

+0

請發佈逐字錯誤消息。 – 2012-04-19 04:00:02

+0

將其發佈在您的問題中。 – 2012-04-19 04:59:04

回答

9

[[email protected]不是了加密的輸出。這是嘗試在byte []對象上打印或呼叫toString()的結果。 (例如,查看System.out.println(new byte[0]);的結果)

嘗試將加密的byte []直接送回解密函數,並使用new String(dec)來打印結果。如果要查看/保存加密數據爲字符串,請將其編碼爲十六進制或base64。

以下是區別。 byte[]表示一個字節數組。它是二進制數據,一系列8位有符號數字。如果您習慣於僅使用ascii,則一系列byte s和String之間的區別可能看起來微不足道,但有很多方式可以用二進制表示字符串。你所做的加密和解密不關心字符串的外觀,或者數據完全代表字符串;它只是看着比特。

如果要加密字符串,則需要將其轉換爲一系列字節。另一方面,一旦你解密了構成字符串的字節,你就需要將它們轉換回來。 myString.getBytes()new String(myBytea)通常是有效的,但由於他們只使用默認編碼,所以有點草率。如果Alice的系統使用utf-8和Bob使用的utf-16,她的信息對他來說就沒有多大意義。因此,最好使用myString.getBytes("utf-8")new String(myBytea,"utf-8")來指定字符編碼。

下面是從項目的一些功能我工作的,具有示範main函數一起:

import java.security.InvalidKeyException; 
import java.security.KeyFactory; 
import java.security.KeyPair; 
import java.security.KeyPairGenerator; 
import java.security.NoSuchAlgorithmException; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.security.SecureRandom; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.spec.X509EncodedKeySpec; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 
import javax.xml.bind.DatatypeConverter; 

public class RSAExample { 
    private static byte[] h2b(String hex){ 
     return DatatypeConverter.parseHexBinary(hex); 
    } 
    private static String b2h(byte[] bytes){ 
     return DatatypeConverter.printHexBinary(bytes); 
    } 

    private static SecureRandom sr = new SecureRandom(); 

    public static KeyPair newKeyPair(int rsabits) throws NoSuchAlgorithmException { 
     KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); 
     generator.initialize(rsabits, sr); 
     return generator.generateKeyPair(); 
    } 

    public static byte[] pubKeyToBytes(PublicKey key){ 
     return key.getEncoded(); // X509 for a public key 
    } 
    public static byte[] privKeyToBytes(PrivateKey key){ 
     return key.getEncoded(); // PKCS8 for a private key 
    } 

    public static PublicKey bytesToPubKey(byte[] bytes) throws InvalidKeySpecException, NoSuchAlgorithmException{ 
     return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bytes)); 
    } 
    public static PrivateKey bytesToPrivKey(byte[] bytes) throws InvalidKeySpecException, NoSuchAlgorithmException{ 
     return KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(bytes)); 
    } 

    public static byte[] encryptWithPubKey(byte[] input, PublicKey key) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException { 
     Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, key); 
     return cipher.doFinal(input); 
    } 
    public static byte[] decryptWithPrivKey(byte[] input, PrivateKey key) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException { 
     Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     return cipher.doFinal(input); 
    } 


    public static void main(String[] args) throws Exception { 
     KeyPair kp = newKeyPair(1<<11); // 2048 bit RSA; might take a second to generate keys 
     PublicKey pubKey = kp.getPublic(); 
     PrivateKey privKey = kp.getPrivate(); 
     String plainText = "Dear Bob,\nWish you were here.\n\t--Alice"; 
     byte[] cipherText = encryptWithPubKey(plainText.getBytes("UTF-8"),pubKey); 
     System.out.println("cipherText: "+b2h(cipherText)); 
     System.out.println("plainText:"); 
     System.out.println(new String(decryptWithPrivKey(cipherText,privKey),"UTF-8")); 
    } 
} 
+1

真的,打印'新的String(dec)'沒有任何意義。如果您真的想查看二進制數據以進行調試,請使用十六進制。如果'dec'包含在默認平臺編碼中不編碼爲有效字符的字節序列,則String(byte [])'構造函數將跳過它們。這會混淆新手,並讓他們認爲一切都很好。 – 2012-04-19 12:26:13

+0

@GregS,你說得對,我應該強調這種區別。查看修改。 – maybeWeCouldStealAVan 2012-04-19 14:41:10

+0

感謝您的回覆..它是固定的 – Avinash 2012-05-08 04:04:53

-3

「[B @ 4a96a」是不加密的字符串。這是字符串的數據。真正的加密發生在這裏

//add this line to your code, it will work fine. 
"String encryptedValue = new BASE64Encoder().encode(encrypted);" 

現在打印encryptedValue查看加密結果。

+3

的對話中我幫了我很多所有這些都是接受答案的前幾個句子格式不正確的版本。 – 2016-09-11 20:56:23

+0

在接受的答案中,他沒有提到基礎64編碼器。 – 2016-09-11 22:40:09