3

I am looking for the best way to perform the following the current task in java (on windows) :

Thanks to a specific String entered by the user, create a random other String/Key (alpha numeric) "inside" the program, and invisible by the user.

The key has to be the same if we enter the same String.

So basically, I see how to make a random String, but I would like to be sure that an user of this program is not able to find the key given back internally (I actually then use this key for encrypting datas, and therefore I don't want a simple user access to this key).

How can I make that ? Could you show me a running example of code for a proper solution ?

EDIT : I request having the same key for a same String entered by the user, because I need to know this generated key for a next use on my computer then, with another client.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Arsenic
  • 343
  • 2
  • 13
  • 2
    I'd rather use SHA256 (SHA-2) than MD5. – Thomas Aug 24 '12 at 09:03
  • 1
    Can you explain the context of your question? Then we can advise on the best design from a security perspective, followed by how to implement in Java. – Duncan Jones Aug 24 '12 at 09:11
  • @ Duncan : Context : On user side, the user enter an alphanumeric string (given previously) and the program need to generate a key (unfoundable by the user of my program) that is then used for encrypting some datas. Then on my side, I need to know also this key (or to generate it) in order to decrypting these datas. – Arsenic Aug 24 '12 at 09:16
  • Can the key be generated at a server? Then you can keep the secret there. – Thilo Aug 24 '12 at 09:29
  • @ Thilo : I got actually some available servers, but I don't know at all about how to make it. I think it will be too complicated according to my current knowledge. – Arsenic Aug 24 '12 at 09:32

4 Answers4

2

Maybe a salted hash function?

Take the user input, add some secret input, and hash the thing.

(Without the secret input, the user can figure out how to create this himself).

Of course, this string is not random at all. The requirement to have this repeatable precludes randomness. There will be no discernible pattern to these strings, though, so it will look "random".

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • I was thinking the same thing - How can it be both random and repeatable? – Conor Pender Aug 24 '12 at 09:05
  • @ Conor Pender : Because I need to check with another program some file encrypted by the program I am talking about, and I don't see other way for doing that. – Arsenic Aug 24 '12 at 09:07
  • @ Philo : 2 questions : 1) How to add some "secret input" not readable by the user ? 2) how to "hash the thing" . Sorry if it looks like basic questions to you .. – Arsenic Aug 24 '12 at 09:10
  • 1
    "secret input not readable by the user" is not possible with a program deployed at the user's machine (if the user is determined). You can only try to hide it well. That is the DRM dilemma. For generating a hash, you could use Commons Codec: http://commons.apache.org/codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html – Thilo Aug 24 '12 at 09:13
  • @ Thilo : Sorry to ask you this, but could you show me a kind of code for using it "in a proper way" ? I actually don't want to make mistakes on that security side. 2nd question : what do you think about Osd answer ? Thank you for your help anyway – Arsenic Aug 24 '12 at 09:23
2

I really don't know enough about your use case to advise from a security perspective. However, to directly solve the issue of generating a reproducible key from user-supplied input, you can make use of password-based key derivation, in which we treat the user supplied input as a password (edited to be a full example):

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import sun.security.provider.SecureRandom;

public class DerivationExample {

  private static SecretKey makeKeyFromUserInput(String userInput, byte[] salt)
      throws NoSuchAlgorithmException, InvalidKeySpecException {

    SecretKeyFactory factory = SecretKeyFactory
        .getInstance("PBKDF2WithHmacSHA1");
    KeySpec keySpec = new PBEKeySpec(userInput.toCharArray(), salt, 1024, 256);
    byte[] derivedKey = factory.generateSecret(keySpec).getEncoded();
    return new SecretKeySpec(derivedKey, "AES");
  }

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

    // PBKDF2 standard recommends at least 64-bit salt
    // Note: you want to randomly generate this elsewhere and keep it constant
    byte[] salt = new byte[8];
    new SecureRandom().engineNextBytes(salt);

    SecretKey derivedKey = makeKeyFromUserInput(userInput, salt);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, derivedKey, new IvParameterSpec(
        new byte[16]));

    String plaintext = "Hello, World!";
    byte[] cipherText = cipher.doFinal(plaintext.getBytes());

    // Derive key again to demonstrate it is the same
    SecretKey derivedKey2 = makeKeyFromUserInput(userInput, salt);
    cipher.init(Cipher.DECRYPT_MODE, derivedKey2, new IvParameterSpec(
        new byte[16]));

    byte[] plainText = cipher.doFinal(cipherText);
    // Prints "Hello, World!"
    System.out.println(new String(plainText));
  }
}

Provided the salt is kept constant, the resulting key will be reproducible. Share the salt between any other devices needing to produce the same key.

Note: You will need to install the unrestricted policy files (see bottom of this page) for this example to work.

Please remember that a security system composed of "secure" bits and pieces is not guaranteed to be secure when viewed as a whole. We've only seen a snippet of your requirements and as such our advice should be taken with a pinch of salt (no pun intended). For a more complete answer, we'd need to understand the end-to-end process you are trying to secure.

However, as StackOverflow is not the place to design a security system, you may need to seek this help elsewhere.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
  • Hello, Thank you for your help and answer. May I ask your opinion about code proposed by @Osd please ? Do you think that your code is more "secured" ? What are the advantage and disadvantage between your and his code if I may ask ? Thank you for your help – Arsenic Aug 24 '12 at 09:56
  • @user1622062 The solution proposed by Osd is a very simple example of salting a hash. My example makes use of a [peer-reviewed method](ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2_1.pdf) for converting passwords to keys, involving salting and multiple iterations of a hash function. My approach is more secure and should be used in preference to the other solution. – Duncan Jones Aug 24 '12 at 09:58
  • 2 questions : Does this method return a String ? what kind of argument do I have to use for "salt" ? – Arsenic Aug 24 '12 at 10:09
  • @user1622062 This method returns a byte array. You can import this as a symmetric key in Java and use it to encrypt. The salt argument is a byte array. This should be a value that you share between every entity that needs access to the key. – Duncan Jones Aug 24 '12 at 11:25
  • Also, if you could show how I can call it, and how to set the argument salt, I would be most grateful. – Arsenic Aug 24 '12 at 12:34
  • Thank you so much for being like helpful. However, I got back the following exception : "Exception in thread "main" java.security.InvalidKeyException: Illegal key size" It seems to come at the line for initiating the cipher.init – Arsenic Aug 24 '12 at 13:08
  • Furthermore, I want use your code for my program but I am facing the following problem : http://stackoverflow.com/questions/12109877/pbekeyspec-with-non-ascii-argument-in-java – Arsenic Aug 24 '12 at 13:09
  • Concerning the file to download, are you talking about : "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7" ? – Arsenic Aug 24 '12 at 13:21
  • If you are using Java 7, yes. Please try some things yourself and Google before you query everything here. This comment thread has continued for long enough. – Duncan Jones Aug 24 '12 at 13:25
  • Also one question, Is there a way to contact you more "directly" if you see what I mean? You seems really experienced in that field, and I am also interested, if you are ok with that ;) – Arsenic Aug 24 '12 at 13:25
  • btw I still receive the following error "Exception in thread "main" java.security.InvalidKeyException: Illegal key size at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1024) at javax.crypto.Cipher.implInit(Cipher.java:790) at javax.crypto.Cipher.chooseProvider(Cipher.java:849) at javax.crypto.Cipher.init(Cipher.java:1348) at javax.crypto.Cipher.init(Cipher.java:1282) at DerivationExample.main(DerivationExample.java:37)" – Arsenic Aug 24 '12 at 13:27
0

I'm not so sure on what you want to achieve, but I think you can use hash to encrypt your string.

Maybe this link can help: How can I generate an MD5 hash?

It is better if you "salt" the string first before you hash the string.

Community
  • 1
  • 1
nic
  • 2,125
  • 1
  • 18
  • 33
0

If you were only expecting a relatively small amount of inputs, you could use the unicode of the characters along with a Random to generate a random number, but store all results in a map. This way you wouldn't repeat the generation of a value if it had already been made, but would instead use the cached value.

Conor Pender
  • 1,071
  • 1
  • 14
  • 30
  • 1
    except when you have to do this again on another machine where the map is not available. And when the map is lost, you're in big trouble. – Thilo Aug 24 '12 at 09:15
  • Very good point, but it might be a valid solution if the entire process is on one machine. – Conor Pender Aug 24 '12 at 09:30
  • I see your point, but sadly this have to be run in different machine. But anyway, thank you for having tried to help me. – Arsenic Aug 24 '12 at 09:33