从字符串生成密钥?

时间:2012-03-02 16:30:30

标签: java cryptography key

我需要从字符串生成一个Key,这样我总是可以从同一个字符串创建相同的键。 (特别是一个Key对象,这样我就可以用它来创建一个Cipher来创建一个SealedObject)

这在Java中是否可行,我应该考虑使用哪种类/方法组合?

4 个答案:

答案 0 :(得分:17)

对于AES加密:

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));

类似地,已弃用的PBKDF1和不安全的DES用于与旧系统进行通信或学习目的

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);
...

请注意,迭代计数在上一个示例中也太低了。

答案 1 :(得分:4)

您想使用PBKDF2bcrypt。前者在我的经验中被更广泛地使用。基于此comment,似乎java确实支持这一点。

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");

答案 2 :(得分:2)

这些都过时了。唯一推荐的算法是 Argon2id。它在 Bouncycastle 的较新版本中: https://www.bouncycastle.org/latest_releases.html

如果内存不足,请在执行参数中使用“-Xmx8G”。

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;
}

答案 3 :(得分:0)

您可以通过加密Java来实现这一目标。

首先你需要两个罐子:

  1. bcmail-jdk16-1.46.jar
  2. bcprov-jdk16-1.46.jar
  3. 以下是Java中Data Encryption Standard的完整示例:

    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);
        }
    }
    

    用法:

    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);
    

    希望这会对你有所帮助。