2017-02-27 142 views
2

所以我想弄清楚如何在java中加密和解密RSA。加密通過javas API完成,並通過biginteger解密。我完成了,但是biginteger有時會給我奇怪的輸出。這是我的代碼:使用java RSA加密並使用BigInteger解密

import java.math.BigInteger; 
import java.security.InvalidKeyException; 
import java.security.KeyPair; 
import java.security.KeyPairGenerator; 
import java.security.NoSuchAlgorithmException; 
import java.security.NoSuchProviderException; 
import java.security.Security; 
import java.security.interfaces.RSAPrivateKey; 
import java.security.interfaces.RSAPublicKey; 
import java.security.spec.InvalidKeySpecException; 

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

import org.bouncycastle.jce.provider.BouncyCastleProvider; 

public class cryptoAndBigIntegerFIX { 
    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException{ 
     Security.addProvider(new BouncyCastleProvider()); 
     System.out.println("input <> encrypted <> decrypted"); 
     cryptoAndBigIntegerFIX.keygen(); 

     BigInteger encryptbytes; 
     BigInteger decryptbytes; 

     //Multiple tests with powers of 3 for some reason :D 
     for(int i=1;i<1000;i*=3){ 
      encryptbytes = cryptoAndBigIntegerFIX.encrypt(new BigInteger(""+i)); 
      System.out.print(i + " <> " + encryptbytes.intValue() + " <> "); 
      decryptbytes = cryptoAndBigIntegerFIX.decrypt(encryptbytes); 
      System.out.println(decryptbytes.intValue());    
     } 
    } 

    public static RSAPrivateKey priv; 
    public static RSAPublicKey pub; 

    public static void keygen() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException{ 
     KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); 

     generator.initialize(512); 
     KeyPair keyPair = generator.generateKeyPair(); 
     priv = (RSAPrivateKey) keyPair.getPrivate(); 
     pub = (RSAPublicKey) keyPair.getPublic();  
    } 

    //Encrypt with javas API 
    public static BigInteger encrypt(BigInteger bg) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException{ 
     byte[] encoded; 
     Cipher cipher=Cipher.getInstance("RSA/ECB/NoPadding"); 
     cipher.init(Cipher.ENCRYPT_MODE, pub); 
     encoded=cipher.doFinal(bg.toByteArray()); 
     return new BigInteger(encoded); 
    } 

    //Decrypt manually 
    public static BigInteger decrypt(BigInteger bg){ 
     BigInteger decoded = bg.modPow(priv.getPrivateExponent(),priv.getModulus()); 
     return decoded; 

    } 

} 

這使輸出爲:

input <> encrypted <> decrypted 
1 <> 1 <> 1 
3 <> 1088098617 <> 3 
9 <> 1947497039 <> 9 
27 <> -1665331145 <> 27 
81 <> -1064046970 <> 81 
243 <> -599005266 <> 243 
729 <> -1534949160 <> 729 

這是正確的,因爲我想加密和解密三種權力。 但有時它會給出錯誤的輸出,如:

input <> encrypted <> decrypted 
1 <> 1 <> 1 
3 <> 1693488667 <> 3 
9 <> -924345856 <> 9 
27 <> 777525903 <> 144224668 
81 <> -1602799071 <> 765474161 
243 <> -227258229 <> 243 
729 <> 1097077312 <> 296615835 

這很奇怪嗎?任何想法我的代碼有什麼問題?這是biginteger還是我生成密鑰的方式?

+0

爲什麼? 'Cipher'提供了一個解密模式以及一個加密模式。 – EJP

+0

這是我的講師給出的「任務」,以證明他們是同一件事。他回覆給我說我也需要做一個JUNIT測試。他沒有對我在上面顯示的這些錯誤提出任何意見,所以也許他沒有注意到這些錯誤,因爲他編譯時沒有得到任何錯誤的答案。事情是,當我有時得到錯誤的答案時,我甚至不能做出JUNIT測試用例。 – David

回答

4

有兩個錯誤在代碼中,固定這些結果中正確的輸出:

  • RSA返回一個字節數組,表示一個無符號(大端)值的編碼,而BigInteger構造期望一個簽署的(大端)值;
  • 您將您的〜512位整數轉換爲32位int使用intValue,這是縮小轉換(即您失去了大部分信息);

要解決這個問題在使用下面的代碼的主:

for (int i = 1; i < 1000; i *= 3) { 
    encryptbytes = encrypt(new BigInteger("" + i)); 
    decryptbytes = decrypt(encryptbytes); 
    System.out.printf("%d <> %d <> %d%n", i, encryptbytes, decryptbytes); // <-- CHANGED 
} 

並修復encrypt方法是這樣的:

public static BigInteger encrypt(BigInteger bg) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException{ 
    byte[] encoded; 
    Cipher cipher=Cipher.getInstance("RSA/ECB/NoPadding"); 
    cipher.init(Cipher.ENCRYPT_MODE, pub); 
    encoded=cipher.doFinal(bg.toByteArray()); 
    // always return a positive number, all numbers in RSA range from 0 to N, the modulus 
    return new BigInteger(1, encoded); // <-- CHANGED 
} 

輸出:

1 <> 1 <> 1 
3 <> 5391244976364305547335484748020521942086098609617330384518129302949818422340576199311962549547267600132422679070440104879858341377467952359964277978034437 <> 3 
9 <> 6124821216540311592072512276604516925109106437800474377305024835746311326643844937438898166014089888517013623381274703706957136996030394061334489396421471 <> 9 
27 <> 7417955231776825208837885603385850571492475371613109504900294367112291012186031184819506881671785651668774452694772296927652149185293472327267855826108811 <> 27 
81 <> 4379633872520787556108807271103986910459839084415924804306544674047140392288351081810043910720852387318488882506988222018682090612584816530149697340650488 <> 81 
243 <> 7246933972891920591130671309726014055879369415307203680175037003794552795366338573568427805702031164261947749468386326443821678079330776559688467025349997 <> 243 
729 <> 1545447812776244759821683256943744637177323415383752406121617316817182282617298911713206245407992744746920675542053503316837741108184755354755351275313816 <> 729 

警告其他讀者:從不使用明文/生RSA("RSA/ECB/NoPadding"在Java中),它是不安全的。改爲使用RSA OAEP嘗試一個混合密碼系統。做不是複製/粘貼上面的代碼。

+0

謝謝!我懷疑這與它有關。但我不知道解決方案,真棒!而且,是的,只是因爲這是一個學校任務。 – David