我需要从一个字符串生成一个密钥,使得我可以始终从相同的字符串创建相同的密钥。(具体来说是一个Key对象,以便我可以使用它创建Cipher,进而创建SealedObject)
在Java中是否可能实现这一目标,我应该查看哪个类/方法组合来完成?
我需要从一个字符串生成一个密钥,使得我可以始终从相同的字符串创建相同的密钥。(具体来说是一个Key对象,以便我可以使用它创建Cipher,进而创建SealedObject)
在Java中是否可能实现这一目标,我应该查看哪个类/方法组合来完成?
对于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);
...
注意,最后一个示例中的迭代次数也太少了。
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");
这些都已经过时了。现在唯一推荐的算法是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;
}
你可以通过Java加密来实现这个目标。
首先,您需要两个Jars:
以下是如何在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);
}
}
使用方法:
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
的类执行加密/解密也没有什么希望。 - Maarten Bodewes
hashCode()
对你来说不够用吗?如果不够用,为什么? - amit