Generate Key from string?
Asked Answered
N

4

13

I need to generate a Key from a string, such that I can always create the same key from the same string. (Specifically a Key object, so that I can use it to create a Cipher in turn to create a SealedObject)

Is this possible in Java, and what class/method combination should I be looking at to do so?

Nagel answered 2/3, 2012 at 16:30 Comment(3)
won't hashCode() do for you? if not - why?Mona
en.wikipedia.org/wiki/…Caracas
Not as far as I'm aware, because I'm trying to create a SealedObject in order to encapsulate an object for transmission: I'm not trying to obfuscate the plaintext string into a hash, I'm trying to create a Key (object)Nagel
C
22

For AES encryption:

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);

byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));

// reinit cypher using param spec
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));

Similarly for the deprecated PBKDF1 and insecure DES for communicating with legacy systems or learning purposes:

byte[] salt = {
    (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
    (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};

int count = 20;

PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count);
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

SealedObject sealed = new SealedObject(object, cipher);
...

Note that the iteration count is too low as well in the last example.

Cripps answered 2/3, 2012 at 16:42 Comment(6)
Thanks. Just to be clear, if I performed the same on the server side with the same password, it would produce a cipher that could be used to decrypt the SealedObject?Nagel
That is correct. As long as you're using the same param and key specs, you will have the same key.Cripps
This would have been a better answer if you removed the first half. DES is completely broken today, and it is dangerous to use it even as an example (people might copy it without knowing that it was unsafe).Token
DES is even for these type of things very very outdated. It is both breakable and if you ever user it for anything which has security requirments the presence of straight des will likely give you troubleHanzelin
Thanks for the extra details, guys. I'll be sure to use the AES version.Nagel
Can it be used for RSA?Privy
H
5

You want to use PBKDF2 or bcrypt for this. The former is more widely used in my experience. It appears, based on this comment, that java does support this.

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Hanzelin answered 3/3, 2012 at 8:38 Comment(0)
R
2

This is all outdated. The only remcoomended algorithm ist Argon2id. It is in the newer Versions of Bouncycastle: https://www.bouncycastle.org/latest_releases.html

If you run out of memory, use "-Xmx8G" in the execution arguments.

private SecretKey genKey(char[] passwordChars, byte[] saltBytes) {
SecretKey aesKey;
    int aesKeyLen = 16; //key len in bytes
    int version = Argon2Parameters.ARGON2_VERSION_13;
    int iterations = 1;
    int memory = 22; // 20 = 1 GB -> 22=4GB
    int parallelism = 16; //double CPU core
    Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
            .withVersion(version).withIterations(iterations).withMemoryPowOfTwo(memory) // use 2^(memory) KB
            .withParallelism(parallelism).withSalt(saltBytes);
    Argon2BytesGenerator gen = new Argon2BytesGenerator();
    gen.init(builder.build());
    byte[] result = new byte[aesKeyLen];
    gen.generateBytes(passwordChars, result, 0, result.length);
    aesKey = new SecretKeySpec(result, "AES");
//clear to free RAM
    builder = null;
    gen = null;
    System.gc();
return aesKey;
}
Rau answered 9/5, 2021 at 16:20 Comment(1)
I mean, it’s a 9 year old question.... it’s not entirely surprising that the answers are outdated nowNagel
L
0

You can achieve this by Encryption of Java.

At first you need two jars:

  1. bcmail-jdk16-1.46.jar
  2. bcprov-jdk16-1.46.jar

Here is complete example of how to Data Encryption Standard in Java:

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

import org.bouncycastle.util.encoders.Base64;


public class KeyGen {
    private SecretKey key;
    private Cipher ecipher;
    private Cipher dcipher;
    private static KeyGen keyGen;

    private KeyGen() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException{
        key = KeyGenerator.getInstance("DES").generateKey();
        ecipher = Cipher.getInstance("DES");
        dcipher = Cipher.getInstance("DES");
        ecipher.init(Cipher.ENCRYPT_MODE, key);
        dcipher.init(Cipher.DECRYPT_MODE, key);
    }

    public static KeyGen getInstance() throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException {
        if(keyGen == null) {
            keyGen = new KeyGen();
        }
        return keyGen;
    }

    public String encrypt(String str) throws UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
        byte[] utf8 = str.getBytes("UTF8");
        byte[] enc = ecipher.doFinal(utf8);
        return new String(Base64.encode(enc));
    }

    public String decrypt(String str) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        byte[] dec = Base64.decode(str);
        byte[] utf8 = dcipher.doFinal(dec);
        return new String(utf8, "UTF8");
    }

    public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
        KeyGen keyGen = KeyGen.getInstance();
        String string = "JOYMAA";
        String enc = keyGen.encrypt(string);
        System.out.println(enc);
        String dec = keyGen.decrypt(enc);
        System.out.println(dec);
    }
}

Usage:

KeyGen keyGen = KeyGen.getInstance();
String string = "JOYMAA";
String enc = keyGen.encrypt(string);
System.out.println(enc);
String dec = keyGen.decrypt(enc);
System.out.println(dec);

Hope this will help you.

Lines answered 2/3, 2012 at 17:21 Comment(1)
Neither does ECB mode encryption. Having a class named KeyGen performing encryption/decryption does not give much hope either.Davita

© 2022 - 2024 — McMap. All rights reserved.