3

I'm trying to adopt RSA algorithm for encrypting String objects, but seems that BigInteger -> String and String -> BigInteger conversions do not work properly. Here's my code:

public class RSAEncryptor {

    private BigInteger n, d, e;

    public RSAEncryptor(int bitlen) {
        SecureRandom r = new SecureRandom();
        BigInteger p = new BigInteger(bitlen / 2, 100, r);
        BigInteger q = new BigInteger(bitlen / 2, 100, r);
        n = p.multiply(q);
        BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
        e = new BigInteger("3");
        while (m.gcd(e).intValue() > 1) {
            e = e.add(new BigInteger("2"));
        }
        d = e.modInverse(m);
    }

    public String encrypt(String message) {
        BigInteger plaintext = new BigInteger(message.getBytes());
        return new String(plaintext.modPow(e, n).toByteArray());
    }

    public String decrypt(String message) {
        BigInteger plaintext = new BigInteger(message.getBytes());
        return new String(plaintext.modPow(d, n).toByteArray());
    }
}

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        RSAEncryptor encryptor = new RSAEncryptor(64);

        String source = "1";
        String crypted = encryptor.encrypt(source);
        System.out.println(crypted);
        String decrypted = encryptor.decrypt(crypted);
        System.out.println(decrypted);
    }
}

It prints not what is expected, and a strange thing is that every time the output differs. Am I doing something wrong? Thanks

2
  • Can you show us some results from the excercise? Commented Apr 28, 2011 at 12:51
  • Sure. 1) encrypted: ��>�Q decrypted: :�I�dG�� 2) encrypted: �:� decrypted: �IQ�� 3) encrypted: �:� decrypted: x�;�4� These are the results of three consecutive runs. Commented Apr 29, 2011 at 9:12

3 Answers 3

2

Encrypted message is an arbitrary byte[], it's not guaranteed that it can be correctly converted to String with particular character encoding, so there is no need to convert it to String.

Another trick is that plaintext should be less than n, otherwise algorithm would produce garbage. When this condition is met, it works fine for me.

Yet another possible problem is that when the first byte of message in greater or equal than 0x80, a negative plaintext would be produced. It can be solved by prepending a zero byte to the bytes of message before converting it to BigInteger, and stripping that byte during inverse conversion.

Sign up to request clarification or add additional context in comments.

Comments

0

Hint: What does getBytes do that's different from the string value of message? Why aren't you just doing BigInteger(message); ?

1 Comment

It throws a NumberFormatException this way, here's the stack trace: ' Exception in thread "main" java.lang.NumberFormatException: For input string: "string" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:449) at java.math.BigInteger.<init>(BigInteger.java:316) at java.math.BigInteger.<init>(BigInteger.java:451) at rsa.RSAEncryptor.encrypt(RSAEncryptor.java:32) at rsa.Main.main(Main.java:20) '
0
import java.math.BigInteger;     
import java.security.SecureRandom;

public class RSA {  
   private final static BigInteger one      = new BigInteger("1");  
   private final static SecureRandom random = new SecureRandom();

   private BigInteger privateKey;  
   private BigInteger publicKey;  
   private BigInteger modulus;   

   // generate an N-bit (roughly) public and private key  
   RSA(int N) {  
      BigInteger p = BigInteger.probablePrime(N/2, random);  
      BigInteger q = BigInteger.probablePrime(N/2, random);   
      BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));       
      modulus    = p.multiply(q);                                          
      publicKey  = new BigInteger("65537");       
   // common value in practice = 2^16 + 1
      privateKey = publicKey.modInverse(phi);   
   }


   BigInteger encrypt(BigInteger message) {    
      return message.modPow(publicKey, modulus);    
   }  

   BigInteger decrypt(BigInteger encrypted) {     
      return encrypted.modPow(privateKey, modulus);    
   }    

   public String toString() {    
      String s = "";    
      s += "public  = " + publicKey  + "\n";   
      s += "private = " + privateKey + "\n";    
      s += "modulus = " + modulus;    
      return s;    
   }    

   public static void main(String[] args) {    
      int N = Integer.parseInt(args[0]);    
      RSA key = new RSA(N);    
      System.out.println(key);    
      // create random message, encrypt and decrypt   
      BigInteger message = new BigInteger(N-1, random);   
      //// create message by converting string to integer   
      // String s = "test";    
      // byte[] bytes = s.getBytes();    
      // BigInteger message = new BigInteger(s);    
      BigInteger encrypt = key.encrypt(message);    
      BigInteger decrypt = key.decrypt(encrypt);    
      System.out.println("message   = " + message);    
      System.out.println("encrpyted = " + encrypt);    
      System.out.println("decrypted = " + decrypt);    
   }     
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.