3
\$\begingroup\$

I'm trying to make it so that a string generates n keys, and all of those are required to recover the original string. For this, I generate n-1 random strings, XOR them all together with the original string to get the nth one. XORing these n strings reproduces the original strings

How secure is this? Is there any better method?

Also, is the code itself good enough? What can I do to improve it in terms of security/speed/readability/best practices?

package crypto;

import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;

/**
 * Created by hooda on 2/3/2015.
 */
public class XOR {

    //Testing the functionality.
    public static void main(String[] args) throws Exception {
        XOR xor = new XOR();

        String text = "Mr. and Mrs. Dursley, of number four Privet Drive, were proud to say that they were perfectly normal, thank you very much.";
        String[] pieces = xor.encrypt(text, 5);
        System.out.println(pieces[0]);
        System.out.println(pieces[1]);
        System.out.println(pieces[2]);
        System.out.println(pieces[3]);
        System.out.println(pieces[4]);
        String test = xor.decrypt(pieces);
        System.out.println(test);

    }

    public String[] encrypt(String s, int n) throws Exception {
        int length = s.length();
        String[] pieces = new String[n];

        for (int i = 0; i < n - 1; i++) {
            pieces[i] = keyGen(length);
        }

        String nth = s;
        for (int i = 0; i < n - 1; i++) {
            nth = doXOR(pieces[i], nth);
        }

        pieces[n - 1] = nth;
        return pieces;
    }

    public String decrypt(String[] pieces) {

        String decrypted = new String(new char[pieces[0].length()]).replace("\0", Character.toString((char) 0));
        for (String piece : pieces) {
            decrypted = doXOR(piece, decrypted);
        }
        return decrypted;
    }

    public String toBinary(String s) throws Exception {
        byte[] bytes = s.getBytes("ASCII");
        StringBuilder binary = new StringBuilder();
        for (byte b : bytes) {
            int val = b;
            for (int i = 0; i < 8; i++) {
                binary.append((val & 128) == 0 ? 0 : 1);
                val <<= 1;
            }
        }
        return binary.toString();
    }


    public String keyGen(int length) throws UnsupportedEncodingException {
        SecureRandom srand = new SecureRandom();
        byte[] bytes = new byte[length];
        srand.nextBytes(bytes);
        return new String(bytes, "ASCII");
    }

    public String doXOR(String s1, String s2) throws IllegalArgumentException {

        String ret;
        if (s1.length() != s2.length()) {
            throw new IllegalArgumentException("The bit strings must have equal length!");
        } else {
            ret = "";
            for (int i = 0; i < s1.length(); i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                int i1 = (int) c1;
                int i2 = (int) c2;
                int i3 = i1 ^ i2;
                char c3 = (char) i3;
                ret += c3;
            }
        }
        return ret;
    }
}
\$\endgroup\$
2
\$\begingroup\$
  • Security. xor is an associative operation.

        nth ^= pieces[0];
        nth ^= pieces[1];
        ...
        nth ^= pieces[n-2]
    

    like your code does is as good as

        nth ^= (pieces[0] ^ pieces[1] ^ ... ^ pieces[n-2]
    
  • doXOR is way too verbose to my taste.

  • toBinary doesn't belong here (and is never called indeed, unless I am missing something). Obviously all the keys you have generated collapse into a single one. The bad guy doesn't have to recover all the keys - he only needs their accumulated xor. There is no additional security.

\$\endgroup\$
  • \$\begingroup\$ Yes, it is obvious now. I may as well be using only one key. Can you suggest an alternative way? \$\endgroup\$ – hoodakaushal Mar 16 '15 at 6:48
0
\$\begingroup\$

The one time pad is not really a secure encryption algorithm.

It leaks information, since it does not provide perfect secrecy (The cypher text should not reveal any information about the plain text). Even if it only leads to assumptions, one can still perform statistical analysis to discover the real meaning.


Example:

You have 2 messages (m1,m2) , which you will encrypt with a key k

Enc(m1,k)=m1⊕k
Enc(m2,k)=m2⊕k

If an attacker manages to intercept both encrypted messages, he can perform a xor on it and end up with the xor-ed plain texts.

(m1⊕k)⊕(m2⊕k)=m1⊕m2

But there is an even more important problem! Due to the re-use of the key for each message, if an attacker manages to guess/knows one of your plaintext messages, they can find your key:

(m1⊕k)⊕m1=k

This results in them being able to read every single encrypted message you sent (encrypted by that key).


Also the 2 time pad and many time pad are considered unsafe. In case you need a more secure encryption algorithm, may I suggest to look into AES and RSA.

\$\endgroup\$
  • \$\begingroup\$ Yes, but that depends on me using the same key for two messages. This is not the case. \$\endgroup\$ – hoodakaushal Mar 16 '15 at 6:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.