1

In the following snippet I try to print encrypted array in a simple string format.

        KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
        SecretKey secretKey = keyGenerator.generateKey();
        Cipher cipher = Cipher.getInstance("Blowfish"); 
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        String input = "password";
        byte encrypted[] = cipher.doFinal(input.getBytes());
        String s = new String(encrypted);
        System.out.println(s);

But what I get is `┐╫Y²▓ô┴Vh¬∙:╪⌡¶ . Why is it ? How can I print it in the proper string format ?

saplingPro
  • 20,769
  • 53
  • 137
  • 195
  • 5
    Well, you encrypted a string. That is what you get when you print it - encryption does not necessarily transform a readable String to another readable string... That is what you wanted: others are not able to see what it is. You need to decrypt it first. – ppeterka Aug 15 '13 at 13:16
  • 1
    @ppeterka this is not the encrypted string. – saplingPro Aug 15 '13 at 13:17
  • 2
    Don't try to put binary data in to strings. That's platform dependent and only leads to problems. If you need it as a string (like saving portably to a text file), use base64. – kiheru Aug 15 '13 at 13:17
  • 1
    @saplingPro: The result of encryption isn't a string to start with. It's arbitrary binary data. You need to use base64 or hex (or something similar) to convert it into some text - but then it still won't be human-readable, of course... that will just be a textual representation of the binary data. – Jon Skeet Aug 15 '13 at 13:17
  • 1
    You mean `byte encrypted[] = cipher.doFinal(input.getBytes());String s = new String(encrypted);` is not the encrypted? Then what is it? – ppeterka Aug 15 '13 at 13:17
  • 3
    As an aside, `input.getBytes()` will use the platform-default encoding. Not a good idea. You should pretty much *always* specify an encoding when converting like this - and it should usually be UTF-8. – Jon Skeet Aug 15 '13 at 13:19
  • @ppeterka I mean of the form _f250d7a040859d66541e2ab4a83eb2225d4fff880f7d2506_ – saplingPro Aug 15 '13 at 13:29
  • 1
    @saplingPro You're looking for hex encoding, if you want output exactly like "f250d7a040859d66541e2ab4a83eb2225d4fff880f7d2506" (http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java) – Pete Scott Aug 15 '13 at 13:32
  • 2
    @saplingPro: One important question to ask yourself: why did you *expect* your code to produce a hex representation of your byte array? – Jon Skeet Aug 15 '13 at 13:36
  • @ppeterka To be more specific, it's not possible to encrypt a string, because a cipher encrypts bytes. – ntoskrnl Aug 16 '13 at 05:26

4 Answers4

0

Encode the bytes in Base64 encoding (How do I convert a byte array to Base64 in Java?)

Or Hex: How to convert a byte array to a hex string in Java?

System.out.println( Hex.encodeHexString( bytes ) );

Community
  • 1
  • 1
Pete Scott
  • 1,516
  • 10
  • 10
0

You could use Base64 encoding from common-codec.

    KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
    SecretKey secretKey = keyGenerator.generateKey();
    Cipher cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    String input = "password";
    byte encrypted[] = cipher.doFinal(input.getBytes());
    System.out.println(new String(Base64.encodeBase64(encrypted)));

Output:

8KA8ahr6INnY4qqtzjAJ8Q==
ThomasEdwin
  • 2,035
  • 1
  • 24
  • 36
0

Most cryptographic algorithms (including blowfish) deal with binary data meaning that it will take binary data in and split out binary data that has been transformed by the algorithm (with the provided specs).

Binary data, as you know is != to string data, however binary data can be represented as string data (using hex, base64, etc).

If we look at your example code we can see this line:

byte encrypted[] = cipher.doFinal(input.getBytes());

This is what it is doing step by step:

  1. It first converts string data into a binary data equivalent using the platform's default charset (NOT RECOMMENDED, but irrelevant).

  2. It is passing the binary data (in form of a byte array) to the method doFinal().

  3. The doFinal() method is processing this byte array via the specifications specified in the statements prior to this line (Blowfish, encryption).

  4. The doFinal() statement is returning a byte array which represents the processed (encrypted, in your case) data.

The fact that the data originally came from a string is no longer relevant because of the nature of the encryption operation does not account for the source or type of the data. The encrypted byte array now contains data that may not be valid charset encoded string. Trying to use a character set to decode the string would most likely result in garbage output as the binary data is no longer a valid string.

However, binary data can be represented directly by outputting the VALUE of the actual bytes rather than what the charset equivalent mapping is (e.g A byte may have the value of 97, which represented in hex is: 0x61 but decoded via ASCII results in the character 'a').

Consider this code to output your encrypted data in hex:

KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("Blowfish"); 
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
String input = "password";
byte encrypted[] = cipher.doFinal(input.getBytes());

StringBuilder str = new StringBuilder();

for(byte b:encrypted){
     str.append(String.format("%02x", b));
}

String encData = str.toString();
System.out.println(encData);

P.S: Don't use getBytes() without any arguments! Supply your own charset like UTF-8. Do as follows:

byte encrypted[] = cipher.doFinal(input.getBytes(Charset.forName("UTF-8")));
initramfs
  • 8,275
  • 2
  • 36
  • 58
0

You can try with:

new String(bytes, StandardCharsets.UTF_8)
z atef
  • 7,138
  • 3
  • 55
  • 50