0

I have a unit test I was trying to write for a generateKey(int **length**) method. The method: 1. Creates a byte array with size of input parameter length 2. Uses SecureRandom().nextBytes(randomKey) method to populate the byte array with random values 3. Encodes the byte array filled with random values to a UTF-8 String object 4. Re-writes the original byte array (called randomKey) to 0's for security 5. Returns the UTF-8 encoded String

I already have a unit test checking for the user inputting a negative value (i.e. -1) such that the byte array would throw a Negative array size exception.

Would a good positive test case be to check that a UTF-8 encoded String is successfully created? Is there a method I can call on the generated String to check that it equals "UTF-8" encoding?

I can't check that the String equals the same String, since the byte array is filled with random values each time it is called....

source code is here:

public static String generateKey(int length) {
    byte[] randomKey = new byte[length];
    new SecureRandom().nextBytes(randomKey);
    String key = new String(randomKey, Charset.forName("UTF-8"));//Base64.getEncoder().encodeToString(randomKey);
    Arrays.fill(randomKey,(byte) 0);
    return key;
}
ennth
  • 1,698
  • 5
  • 31
  • 63
  • Why? You should just pass around the key as a byte array. String is not a container for binary data. – user207421 Feb 10 '20 at 02:45
  • Oh, so you're suggesting to write a test to do check if the byte array is successfully created? I'm not sure I understand what you're saying. The source code that I explained above, is from, source code, I was only tasked with writing unit tests for it, so I'm not really supposed to change the source code. – ennth Feb 10 '20 at 02:49
  • I'm certain you haven't understood me, but if you don't convert your byte array to a String and back, you don't need to write a test to see whether the conversion was correct. – user207421 Feb 10 '20 at 09:20

2 Answers2

0

You can convert a UTF8 string to a byte array as below

String str = "私の";  // replace this with your generateKey result
byte [] b = str.getBytes();
String newString;
try {
    newString = new String (b, "UTF-8");
    System.out.println(newString);

    System.out.println("size is equal ? " + (str.length() == newString.length()));
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
Scary Wombat
  • 44,617
  • 6
  • 35
  • 64
0

First, the code you posted is simply wrong: you can't take a random array of bytes and treat it as a UTF-8 string, because UTF-8 expects certain bit patterns to indicate multi-byte characters.

Unfortunately, this failure happens silently, because you're using a string constructor that "always replaces malformed-input and unmappable-character sequences with this charset's default replacement string". So you'll get something, but you wouldn't be able to translate it back to the same binary value.

The comment in the code, however, gives you the answer: you need to use Base64 to encode the binary value.

However, that still won't let you verify that the encoded string is equivalent to the original byte array, because the function takes great care to zero out the array immediately after use (which doesn't really do what the author thinks it does, but I'm not going to get into that argument).

If you really want to test a method like this, you need to be able to mock out core parts of it. You could, for example, separate out the generation of random bytes from encoding, and then pass in a byte generator that keeps track of the bytes that it generated.

But the real question is why? What are you (or more correctly, the person writing this code) actually trying to accomplish? And why won't a UUID accomplish it?

parsifal
  • 373
  • 1
  • 5