0

For my java class, part of my project involves getting a encryption key length from the user and rounding that up to the nearest multiple of 1024. The length is passed as a long. In my method I get the long and I get the file path to write to. In examples I've seen this implementation:

try (FileOutputStream out = new FileOutputStream(file)) {
    byte[] bytes = new byte[1024];
    new SecureRandom().nextBytes(bytes);
    out.write(bytes);
}

But where and how do I implement my long variable? I can't put a long in byte[long]. I know I need to used the SecureRandom().nextBytes() according to my professor. Any help would be greatly appreciated because this part has been driving me crazy.

Here is what I have so far but I can't help but think this isn't the way my professor wants it done...

public void oneKeyGenerator(String keyPath, long keyLength) {
        final long CONST_MULTIPLE = 1024;
        try {
            FileOutputStream out = new FileOutputStream(keyPath);
            byte[] bytes = new byte[1024];
            for(long x = 0; x < keyLength/CONST_MULTIPLE; x++) {
                new SecureRandom().nextBytes(bytes);
                out.write(bytes);
            }
        } catch(IOException e){
            gui.fileException(e.getMessage());
        }
    }

2 Answers2

0

You don't have to loop, just allocate a byte array of the size you need:

long roundNext(long v, long multiple) {
    return ((v + multiple - 1) / multiple) * multiple;
}

public void oneKeyGenerator(String keyPath, long keyLength) {
    final long CONST_MULTIPLE = 1024;
    try {
        FileOutputStream out = new FileOutputStream(keyPath);
        byte[] bytes = new byte[(int) roundNext(keyLength, CONST_MULTIPLE)];
        new SecureRandom().nextBytes(bytes);
        out.write(bytes);
    } catch(IOException e){
        gui.fileException(e.getMessage());
    }
}

Hope it helps.

totoro
  • 2,469
  • 2
  • 19
  • 23
  • The line: byte[] bytes = new byte[roundNext(keyLength, CONST_MULTIPLE)]; gives the error: incompatible types: possible lossy conversion from long to int – JoshuaRG1993 Apr 25 '16 at 19:09
  • `new byte[n]` wants `n` to be `int`, but your `keyLength` is `long`. `long` can be bigger than `int`, therefore the warning. In your case your `long` will always be small enough for an `int`. – totoro Apr 25 '16 at 19:14
  • @JoshuaRG1993 I have edited my answer and added a cast to int `(int) roundNext(keyLength, CONST_MULTIPLE)` that you maybe didn't see before. – totoro Apr 25 '16 at 19:22
  • Thank you for the help. Does our two implementations give the same results though? Or is one significantly more efficient? – JoshuaRG1993 Apr 25 '16 at 19:48
  • For very large arrays you should loop to avoid allocating large amounts of memory. If you loop don't make a `new SecureRandom()` every iteration, create an instance outside the loop and reuse it. – totoro Apr 25 '16 at 20:00
0

What you are asking seems kind of odd. Is the requirement that the user's inputted key length must be stored in a long? This would mean that the user could request a key that is a length greater than 2,147,483,647 since that is the max value an int can hold. That would be super huge and sounds ridiculous. You can probably just use an int and not a long. 2 Billion Bytes would be around 2 GB of data.

Encryption keys are usually specified in bits, but still, that would be 260+ MB of data.

You need to break this down into separate problems to solve, and create separate methods.

  1. Get the nearest 1024 multiple in a separate method.
  2. Generate your "encryption key" using SecureRandom in a separate method.
  3. Write that key to a file.

Below I have put a solution that would actually allow you to write the super huge key, but I don't think you really want that, it was more interesting to figure out. You should probably just cast the keySize to an int, and use it like in totoro's answer. This answer is kind of crazy, but it should help guide you and maybe make you re-think what you are doing.

static final long CONST_MULTIPLE = 1024;

private long getNearest1024Multiple(long value)
{
    double divisor = value / (double)CONST_MULTIPLE;
    int multiple = (int)Math.round(divisor);

    if (multiple == 0)
    {
        multiple = 1;
    }

    return multiple * CONST_MULTIPLE;
}

private ByteArrayOutputStream generateLongEncryptionKey(long keySize) throws IOException
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    SecureRandom secureRandom = new SecureRandom();

    while (keySize > 0)
    {
        if (keySize > Integer.MAX_VALUE)
        {
            // The keySize long actually has a super huge value in it, so grab a chunk at a time
            byte[] randomBytes = new byte[Integer.MAX_VALUE];
            secureRandom.nextBytes(randomBytes);

            baos.write(randomBytes);
            keySize -= Integer.MAX_VALUE;
        }
        else
        {
            // We grabbed the last chunk
            byte[] randomBytes = new byte[(int)keySize];
            secureRandom.nextBytes(randomBytes);

            baos.write(randomBytes);
            keySize -= keySize;
        }
    }

    return baos;
}

private void generateAndSaveKey(String keyPath, long userInputKeyLength) throws IOException
{
    long roundedKeyLength = getNearest1024Multiple(userInputKeyLength);
    ByteArrayOutputStream baos = generateLongEncryptionKey(roundedKeyLength);

    FileOutputStream fileOutputStream = new FileOutputStream(keyPath);
    baos.writeTo(fileOutputStream);
}
T. Colligan
  • 161
  • 1
  • 9