我需要从字符串生成一个Key,这样我总是可以从同一个字符串创建相同的键。 (特别是一个Key对象,这样我就可以用它来创建一个Cipher来创建一个SealedObject)
这在Java中是否可行,我应该考虑使用哪种类/方法组合?
答案 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)
您想使用PBKDF2或bcrypt。前者在我的经验中被更广泛地使用。基于此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来实现这一目标。
首先你需要两个罐子:
以下是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);
希望这会对你有所帮助。