2017-02-27 3 views
2

Alors j'essaie de comprendre comment je peux crypter et décrypter RSA en Java. Le cryptage est effectué avec l'API javas et le décryptage avec biginteger. J'ai fini mais biginteger me donne parfois des résultats bizarres. Ceci est mon code:cryptage avec Java RSA et décryptage avec 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; 

    } 

} 

La sortie est ce qui donne:

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

qui est correct que je suis en train de chiffrer et déchiffrer les pouvoirs de trois. Mais parfois, il donne une mauvaise sortie comme:

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

qui est assez bizarre? Une idée de ce qui ne va pas avec mon code? Est-ce un problème avec biginteger ou avec la façon dont je génère des clés?

+0

Pourquoi? 'Cipher' fournit un mode décryptage ainsi qu'un mode crypté. – EJP

+0

C'était une "mission" donnée par mon professeur de prouver qu'ils sont une seule et même chose. Il me l'a renvoyé en disant que je devais faire un test JUNIT aussi. Il n'a rien dit à propos de ces erreurs que je montre ci-dessus alors peut-être qu'il ne les a pas remarqué parce que quand il a compilé il n'a pas eu de mauvaises réponses. La chose est, je ne peux même pas faire un test de JUNIT quand j'ai parfois une mauvaise réponse. – David

Répondre

4

Il y a deux erreurs dans votre code, la fixation de ces résultats dans la production correcte:

  • RSA retourne un tableau d'octets qui représente un codage d'un non signé (big endian) valeur, alors que le constructeur BigInteger attend un signé (gros boutiste) valeur;
  • vous convertissez votre ~ 512 entiers de bits à un 32 bits en utilisant intintValue, qui est un rétrécissement conversion (à savoir que vous perdez la plupart des informations);

Pour résoudre ce problème utilisez le code suivant dans votre principale:

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 
} 

et fixer votre méthode encrypt comme ceci:

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 
} 

Sortie:

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

Avertissement pour les autres lecteurs: jamais décrypté/raw RSA ("RSA/ECB/NoPadding" en Java), il est peu sûr. Essayez un système de cryptage hybride avec RSA OAEP à la place. Ne pas copier/coller au-dessus du code.

+0

Merci! Je me doutais que cela avait quelque chose à voir avec ça. Mais je ne connaissais pas la solution, génial! Et oui, le nopadding est seulement parce que c'est une tâche scolaire. – David