2

I want to enter my own String variable to then turn it into a key for encryption/decryption for AES algorithm. I have tried many known ways such as UTF-8, base64, some methods doing conversion byte-string and vice versa and some other. Although it's true that all of them work even with some of them not working accurately, all of them turn the string in bytes, but what i want is to enter something like "helloWorld" and get back a 128-bit key for AES. Anything i use it goes for "Invalid key length" since the bytes are not accurate. What do i need to do to get the correct bytes? Also i want to clarify that i want String and not an array of char since i want to make it as a function in my programm later so that the user can change the key at will should it be compromised.

UPDATE: i edited the example and this i what i have so far, still throws exception about parameters and key length though

    public class SHAHashingExample
{
    private static byte[] keyValue;

    public static void main(String[] args)throws Exception
    {
        String password = "123456";

        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(password.getBytes());

        byte byteData[] = md.digest();
        keyValue = md.digest();

        //convert the byte to hex format method 1
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < byteData.length/2; i++) {
         sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
        }

        System.out.println("Hex format : " + sb.toString());

        //convert the byte to hex format method 2
        StringBuffer hexString = new StringBuffer();
        for (int i=0;i<byteData.length/2;i++) {
            String hex=Integer.toHexString(0xff & byteData[i]);
            if(hex.length()==1) hexString.append('0');
            hexString.append(hex);
        }
        System.out.println("Hex format : " + hexString.toString());

        String k = "hello world";
        String f = encrypt(k);
        System.out.println(f);
        String j = decrypt(f);
        System.out.println(j);
    }

    public static String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, "AES");
        return key;
    }
}
  • http://en.wikipedia.org/wiki/Key_derivation_function – SLaks Mar 14 '14 at 16:26
  • That doesn't really tell me much, of course that one I didn't find and i am thankfull for your assistance but examples based on derivation i found are too complex or some are used to hash a password for whatever reason. What i want is a simple implementation of somthing like: AESKey ak = hash("mypassword"); somthing simple like that. Of course if a ready-to-go method like that exists then please tell which one it is, if not i would appreciate a very simple example. – Παναγιώτης Νικολαρόπουλος Mar 14 '14 at 17:43
  • So first of all from your code, you are doing dynamic generation of keys when using the `generateKey` routine. In this way you are not actually using your string converted to key using hash as the actual key. You might want to look here as well. http://stackoverflow.com/questions/3451670/java-aes-and-using-my-own-key – trumpetlicks Mar 14 '14 at 18:47
  • that actually is not a problem since the generateKey method uses my own field which is initialized in main. I also changed the parameters to give the key as a parameter after its initialization and it works exactly the same. – Παναγιώτης Νικολαρόπουλος Mar 14 '14 at 18:58

2 Answers2

3

UPDATE 2: Turns out your usage of many components of the Java Cipher capabilities are not spot on. Look here at this other SO answer.

Java AES and using my own Key

UPDATE 1: To get the 256 bit value down to 128 bits using the example below, here is what you may want to try:

// After you already have generated the digest
byte[] mdbytes = md.digest();
byte[] key = new byte[mdbytes.length / 2];

for(int I = 0; I < key.length; I++){
    // Choice 1 for using only 128 bits of the 256 generated
    key[I] = mdbytes[I];

    // Choice 2 for using ALL of the 256 bits generated
    key[I] = mdbytes[I] ^ mdbytes[I + key.length];
}

// Now use key as the input key for AES

ORIGINAL: Here is a great example of using the built-in java APIs for performing a SHA hash on some data bytes.

http://www.mkyong.com/java/java-sha-hashing-example/

Java has built-in capability to perform multiple differing hash types, and you really should try to take advantage of one, instead of trying to write one yourself. Perhaps the most widely used hash functions are the SHA versions. There are versions that can output a 128, 256, and 512 bit hash output.

What you are asking for, is in all technicality exactly how logging into a system using your password generally works. the system never truly stores your actual textual password, but rather the HASH to it. When you, the user, enters your password, the system performs a live hash of what you entered and compares the live generated hash with the stored hash. This does not go the added step of lets say using that hash as an actual key component for a symmetric encryption. In general a GOOD hash can indeed generate DECENT key material for use in actual symmetric encryption / decryption.

Community
  • 1
  • 1
trumpetlicks
  • 7,033
  • 2
  • 19
  • 33
  • this example is good but when i gave the md.digest to my byte[] key and tried AES encryption it went to an exception for Illegal key size or default parameters, and when i changed the SHA-256 to SHA-128 it said that the 128 was not available. this is really frustrating to tell you the truth. – Παναγιώτης Νικολαρόπουλος Mar 14 '14 at 18:19
  • So, SHA-256 outputs a 256 bit value, therefore you will have to either chop down the SHA based output by only using half of it, or perform use all of it by combining the upper 128 bit with the lower 128 bits using an XOR operation into a single 128 bit value. Look at my updated answer. – trumpetlicks Mar 14 '14 at 18:30
  • the digest method worked. also in choice 2 where i hold the 256bits it need a (byte) wrapper(i'm not really good with wrapper theory maybe i'm saying it wrong) to prevent loss of precision. Thanks though. – Παναγιώτης Νικολαρόπουλος Mar 14 '14 at 19:21
0

What you are looking for is called a hash function. You will be able to enter an input of arbitrary length, and the hash function will always output a value of fixed bit size -- 128 bits in your case.

There are many approaches to a hash function. The most simple one would be doing the modulo operation between an input number (an integer representation of your string, for example) and the maximum number that can be represented in n bits (in your case, 128); the output result will be an n-bit number that you can convert to whatever form you want (probably hexadecimal) and use it as an AES key.

That isn't necessarily efficient (which is to say, the output 128-bit keys may not be very evenly distributed between 0 and 2^128 - 1), though -- more importantly, it would be quite slow for no good reason. Some efficient 128-bit hash functions are CityHash and MurmurHash -- you can look more up (as well as several Java implementations) on Google.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
ash_ap
  • 1
  • To clarify, your problem may lie into converting the number into its hexidecimal form, if you're using the key on a specific interface that takes HEX values. That means converting something like 721 (decimal) or 1011010001 (binary), into 2D1. Java's Integer class has a a built-in method to do that, [toHexString](http://www.tutorialspoint.com/java/lang/integer_tohexstring.htm). – ash_ap Mar 14 '14 at 17:59
  • Actually he really does not want to conver to hex STRING unless he wants to display the output from the hash, nor does he really want to convert the string prior to actually performing the hash. – trumpetlicks Mar 14 '14 at 18:07
  • You may be right. It depends on how he wants to use they key afterwards. If he's encrypting something within his application using AES, he probably wants the key in numeric form. – ash_ap Mar 14 '14 at 18:26
  • i simply want from the user's perspective, to give my own key as a string, take that string, store it at a byte[] as a 128-bit key and use it for AES encryption. I always fall on exceptions for key size or parameters. – Παναγιώτης Νικολαρόπουλος Mar 14 '14 at 18:27
  • Technically, there is NEVER a reason to have the key in any other form than the binary numeric representation within the computer, unless of course you are trying to learn or debug by printing the key. It would actually be quite insecure to convert his input string to hex string prior to hashing, because while the output hex string would be longer, the actual amount of characters from the full set would only become 16 (i.e. 0-F) which becomes a potentially more easily crackable password. – trumpetlicks Mar 14 '14 at 18:42
  • well i want this implementation because i am developing a chat program and i want to use a key exchange algorithm and since the server will be communicating with many clients i want its pair to be different. Well then again using the generated keys from the algorithms could probably work too but i want to give the user more options for managing their information. – Παναγιώτης Νικολαρόπουλος Mar 14 '14 at 19:01