-1

I need to convert secretKey.getEncoded() from byte[] to String in order to save the key to db and to send the key via message to another party.

Right now i menaged to do that in Base64 (24 bytes) but the other party can only read it in UTF-8 format (16 bytes)

I tryed to do this: String str = new String(bytes, Charsets.UTF_8); but i get wrong Gibberish format with quation marks like this: k��$��v/~M�6�L�

What is the right way to do this?

 public static String generateAESKey() throws Exception {

    KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
    kgen.init(128); 
    SecretKey secretKey = kgen.generateKey();

    return new String(Base64.encode(secretKey.getEncoded(), Base64.NO_WRAP));

}
Arik6
  • 93
  • 8
  • Can you try `String str = new String(secretKey.toString(), Charsets.UTF_8); ` – Deepak Patankar Jan 04 '20 at 05:09
  • How did you initialize the variable `bytes` ? – Deepak Patankar Jan 04 '20 at 05:10
  • new String(secretKey.getEncoded(), Charsets.UTF_8); – koding Jan 04 '20 at 05:11
  • Why? Your database can hold byte arrays, and you can certainly send them. String is not a container for binary data. – user207421 Jan 04 '20 at 06:01
  • @DeepakPatankar Have you tried that? Are you sure `toString()` does what you want? – user207421 Jan 04 '20 at 06:02
  • @user207421 Thanks a lot for pointing it out. The argument should have been a byte [] in place of string. – Deepak Patankar Jan 04 '20 at 06:17
  • Thank you for your answers, The reason that I insist on converting from byte array to String is becuse i need to do another Encryption to this String, Is there a proper way to convert byte array to UTF-8 String? rihgt now i got this bad Gibberish result: `k��$��v/~M�6�L�` – Arik6 Jan 04 '20 at 15:19
  • 1
    @Arik6 an AES key is a random or pseudorandom (e.g. from a KDF) string of bytes. In your case, 16 bytes corresponds to a 128 bit key. Given that it's random or close to it, why do you expect that trying to interpret those random bytes as a UTF-8 string won't just result in random garbage? I recommend that you and/or the other party hold off on doing cryptography until you understand some of the underlying concepts a bit better--doing cryptography badly can be dangerous for user trust and privacy. – nanofarad Jan 04 '20 at 15:28
  • 2
    @Arik6 some values of UTF-8 are not printable, like the first few which are control bytes. So no, it is not possible converting a byte array having all possible values from 0-255 to a readable string. That's why base64 is used. – Frederik Jan 04 '20 at 15:29
  • Thank you, So from your experience, the only way to save the key to DB or send as message is not convert at all and use the original byth array ? – Arik6 Jan 04 '20 at 15:41
  • 1
    Okay, I don't get it. You claim in the text of your question that you don't know how to convert an binary byte array into a string, and give an example showing why this won't work. Then you show code which does do it the right way and you ask "what is the right way". – President James K. Polk Jan 05 '20 at 02:11
  • @TheFreddy1404: It's a little more complicated than that (read up on UTF-8 coding and invalid UTF-8 byte sequences), but you've got the gist of it. – President James K. Polk Jan 05 '20 at 02:14
  • @Arik6, look at my code. I save your key as hex string. Is that what you want? – koding Jan 05 '20 at 04:38
  • From not only experience and first principles. Why do two conversions instead of zero? Why write redundant code? Why take the risk? Why write code that needs an SO question? – user207421 Jan 05 '20 at 05:22
  • Eventually the other party (IOS) the other side, also converts from/to BASE64, thank you all for your time – Arik6 Jan 05 '20 at 14:10

1 Answers1

1

Generates a key in the form of a byte arrays that you can use to encrypt and decrypt process.

private SecretKey secretKey; // member variables (in class)

public byte[] generateAESKey() {
    try {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        if (secretKey == null) {
            secretKey = kgen.generateKey();
        }
        byte[] keyBytes = secretKey.getEncoded(); 
        //Log.i("keyBytes", toHexString(keyBytes));
        return keyBytes;
    }
    catch (Exception ex){
        ex.printStackTrace();
    }
    return null;
}

result of generateAESKey:

0x04 0x90 0x74 0x21 0x73 0xB9 0x3D 0x1F 0x7B 0x19 0xC4 0x95 0x85 0x20 0xDF 0x27

Generate keys in the form of strings that you can save or send to another app.

public String getStrAESkey()  {
    try {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        if (secretKey == null) {
            secretKey = kgen.generateKey();
        }
        String keyStr = toHexString(secretKey.getEncoded());
        Log.i("keyStr", keyStr);
        return keyStr;
    }
    catch (Exception ex){
        ex.printStackTrace();
    }
    return null;
}

result of getStrAESkey():

0490742173B93D1F7B19C4958520DF27

//

public String toHexString(byte[] bytes) {
    return Utils.printHexBinary(bytes);
}

public byte[] toByteArray(String hexString) {
    return Utils.parseHexBinary(hexString);
}

Utils.java

public class Utils {
    private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

    private static int hexToBin(char ch) {
        if ('0' <= ch && ch <= '9') return ch - '0';
        if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
        if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
        return -1;
    }

    public static byte[] parseHexBinary(String s) {
        final int len = s.length();

        if (len % 2 != 0)
            throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);

        byte[] out = new byte[len / 2];

        for (int i = 0; i < len; i += 2) {
            int h = hexToBin(s.charAt(i));
            int l = hexToBin(s.charAt(i + 1));
            if (h == -1 || l == -1)
                throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);

            out[i / 2] = (byte) (h * 16 + l);
        }

        return out;
    }

    public static String printHexBinary(byte[] data) {
        StringBuilder r = new StringBuilder(data.length * 2);
        for (byte b : data) {
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
        }
        return r.toString();
    }
}
koding
  • 155
  • 1
  • 9
  • Thank you for your answer, but as I write, when I do so I get an incorrect Gibberish String format , for example: `k��$��v/~M�6�L�` – Arik6 Jan 04 '20 at 15:08
  • This is simply incorrect and will likely result in loss of information, reduction of security, and inability to decrypt. Furthermore, this is almost a copy&paste of the method that the OP already said he used and thinks is wrong. – President James K. Polk Jan 05 '20 at 02:08
  • I answer based on references here, https://docs.oracle.com/javase/tutorial/i18n/text/string.html – koding Jan 05 '20 at 03:41