gooner4
gooner4

Reputation: 33

Audio Encryption Using RSA

When i run the below code the decrypted length is different from the original length. So the audio can't be read.

I get this error : javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream

at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1119)
at MainClass.main(MainClass.java:119)

My code is here:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

public class MainClass {
public static final int SIZE = 1024;

private BigInteger p, q, n, totient, e, d;
private Random rnd = new Random();

public MainClass() {

    p = new BigInteger(1024, 10, new Random());
    do {
        q = new BigInteger(1024, 10, new Random());
    } while (p.equals(q));

    n = p.multiply(q);

    totient = (p.subtract(BigInteger.ONE)).multiply(q
            .subtract(BigInteger.ONE));

    // System.out.println(p+"\n"+q+"\n"+n+"\n"+totient);
}

public BigInteger getMod() {
    d = e.modInverse(totient);
    // System.out.println("d="+d);
    return d;
}

public BigInteger getE() {
    do {
        e = new BigInteger(SIZE, rnd);
    } while (!e.gcd(totient).equals(BigInteger.ONE)
            || !(e.compareTo(totient) < 0));
    return e;
}

public String encrypt(String msg) {
    BigInteger ciphertext = new BigInteger(msg.getBytes());
    String cipher = (ciphertext).modPow(getE(), getN()).toString();
    return cipher;
}

public String decrypt(String msg) {
    byte[] decryptMsg = (new BigInteger(msg)).modPow(getMod(), getN())
            .toByteArray();
    String plain = new String(decryptMsg);
    return plain;
}

public BigInteger getN() {
    return n;
}

public static void main(String[] args) {

    try {
        List<String> ori = new ArrayList<String>();
        List<String> st1 = new ArrayList<String>();
        List<String> st2 = new ArrayList<String>();
        String s2;

        MainClass mc = new MainClass();
        // StringHelper sh = new StringHelper();
        byte[] input;
        final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        // final AudioFileFormat.Type [] types =
        // AudioSystem.getAudioFileTypes();
        final String PATH = "C:\\Users\\Rahul\\Desktop\\adios.wav";
        final AudioInputStream audioInputStream = AudioSystem
                .getAudioInputStream(new File(PATH));

        AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE,
                byteOut);
        audioInputStream.close();
        byteOut.close();
        input = ((ByteArrayOutputStream) byteOut).toByteArray();
        System.out.println(input.length);

        input.toString();
        String s = new String(input);
        System.out.println("Original " + s.length() + "\n");

        int i = 0;
        for (i = 0; i + 255 < s.length(); i = i + 256) {
            ori.add(s.substring(i, i + 255));
        }
        ori.add(s.substring(i - 256, s.length() - 1));
        // System.out.println(s.length());
        for (i = 0; i < ori.size(); i++) {
            st1.add(mc.encrypt(ori.get(i)));
        }
        // String s1 = mc.encrypt(s.substring(0, 500));

        // System.out.println("Cipher Text");
        // System.out.println(s1.length()+ "\n"+s1);
        for (i = 0; i < st1.size(); i++) {
            st2.add(mc.decrypt(st1.get(i)));
        }
        // String s2 = mc.decrypt(s1);
        StringBuffer sb = new StringBuffer();
        for (i = 0; i < st2.size(); i++) {
            sb.append(st2.get(i));
        }
        s2 = sb.toString();
        System.out.println("Decrypt" + s2.length() + "\n");
        byte[] output = s2.getBytes();
        ByteArrayInputStream oInstream = new ByteArrayInputStream(output);
        AudioInputStream oAIS = AudioSystem.getAudioInputStream(oInstream);
        AudioSystem.write(oAIS, AudioFileFormat.Type.WAVE, new File(
                "E:\\decrypted.wav"));
        oAIS.close();
        oInstream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

Any help??

Upvotes: 1

Views: 1772

Answers (2)

Neil Coffey
Neil Coffey

Reputation: 21815

You seem to be trying to re-invent the wheel, while making it square into the bargain. Java has a built-in encryption API which I would strongly advise you to use. And you also need to get a full grasp of which encryption to use where.

A key problem you have, aside from your implementation, is that RSA is designed for passing a very small piece of data-- essentially, a key for another algorithm actually used to perform the encryption of the main data. Or put another way if this helps: think of RSA as essentially a key passing scheme, not an "encryption" algorithm per se.

You should:

  • using the standard encryption library, encrypt the data using a symmetric algorithm such as AES: see, for example, my tutorial on symmetric/AES encryption in Java
  • use RSA only as a means of passing to the remote client the (AES etc) key that you used to encrypt the data: again, I've written about using RSA in Java with example code.

I would also really encourage you to read through mine and other people's tutorials to really try and understand what is going on with cryptography. It's quite a complex area and just "diving in" without a good understanding of the basic concepts is likely to lead to you writing insecure code.

Upvotes: 3

CodesInChaos
CodesInChaos

Reputation: 108840

This code is broken in many ways:

  1. You're using an insecure PRNG
  2. p and q should be primes
  3. You're not using padding. RSA requires padding, preferably OAEP
  4. You're open to timing attacks
  5. RSA can only encrypt a few bytes at once. In practice we rarely encrypt actual data with RSA. It's slow, it increases the size of the ciphertext, there is no standardized mode for this,...
  6. Abuse of strings. Your conversion from string to BigInteger is nonsense. You shouldn't use strings at all, you should work with binary data directly.
  7. Not a real problem, but in practice we choose e to be a small prime larger than two such as 3 or 65537. This results in a significant speedup of public key operations.

How you should do this:

  1. Use Java's built in RSA
  2. Generate a new random AES key and encrypt it with RSA
  3. Encrypt actual data with AES in an authenticated mode (AES-GCM for example)
  4. Concat the results of 2. and 3.

Upvotes: 5

Related Questions