在我目前工作的地方,我的任务是编写一个好的加密和解密代码,它将包含DEK和KEK。还没开始用KEK呢。我已经告诉他们,我们需要专家的帮助,但我不认为我会得到任何帮助。任何关于KEK的提示,如何生成它们,以及在哪里存储它们?(HSM ?)我会很感激的。
经过一周的研究,我写了下面的代码。
寻找关于下面代码中的错误以及如何修复它的反馈。另外,我使用GUID作为身份验证标记,它绑定到信息所属的用户。加密的文本和标记存储在不同位置的单独数据库中。我在正确的道路上吗?如果没有请给我看看。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public enum AES {
INSTANCE;
private static final String CIPHER_ALGORITHM = "AES";
private static final String ALGORITHM_MODE_PADDING = "AES/GCM/NoPadding";
private static final int IV_LENGTH_BYTES = 16;
private static final int AES_KEY_SIZE = 128;
private static final int GCM_TAG_LENGTH = 128;
public String encrypt(String plainText, String authenticationTag) throws GeneralSecurityException, IOException {
createKeyFile(authenticationTag);
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
final int blockSize = cipher.getBlockSize();
SecretKey secretKey = readKeyFile(authenticationTag);
byte[] plainTextByte = plainText.trim().getBytes(Charset.forName("UTF-8"));
byte[] ivBytes = generateIV();
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes));
cipher.updateAAD(authenticationTag.getBytes(Charset.forName("UTF-8")));
byte[] encryptedMessage = cipher.doFinal(plainTextByte);
byte iv_and_encryptedMessage[] = concatIvAndCipher(ivBytes, encryptedMessage, blockSize);
Base64.Encoder encoder = Base64.getEncoder().withoutPadding();
String iv_and_encryptedText = encoder.encodeToString(iv_and_encryptedMessage);
return iv_and_encryptedText;
}
public String decrypt(String iv_and_encryptedTextBase64, String authenticationTag)
throws GeneralSecurityException, IOException {
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
final int blockSize = cipher.getBlockSize();
Base64.Decoder decoder = Base64.getDecoder();
byte[] iv_and_encryptedMessage = decoder.decode(iv_and_encryptedTextBase64.trim());
byte[] ivBytes = extractIvFrom(iv_and_encryptedMessage, blockSize);
byte[] encryptedTextBytes = extractEncryptedMessageFrom(iv_and_encryptedMessage, blockSize);
SecretKey secretKey = readKeyFile(authenticationTag);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes));
cipher.updateAAD(authenticationTag.getBytes(Charset.forName("UTF-8")));
byte[] decryptedByte = cipher.doFinal(encryptedTextBytes);
String decryptedMessage = new String(decryptedByte, Charset.forName("UTF-8"));
return decryptedMessage;
}
private SecretKey readKeyFile(String tag) {
}
private void createKeyFile(String tag) {
}
public byte[] generateIV() throws NoSuchAlgorithmException {
SecureRandom random = new SecureRandom();
byte[] ivBytes = new byte[IV_LENGTH_BYTES];
random.nextBytes(ivBytes);
return ivBytes;
}
public byte[] concatIvAndCipher(byte[] iv, byte[] cipher, int blockSize) {
final byte[] ivAndEncryptedMessage = new byte[iv.length + cipher.length];
System.arraycopy(iv, 0, ivAndEncryptedMessage, 0, blockSize);
System.arraycopy(cipher, 0, ivAndEncryptedMessage, blockSize, cipher.length);
return ivAndEncryptedMessage;
}
public byte[] extractIvFrom(byte[] iv_and_encryptedMessage, int blockSize) {
byte[] ivBytes = new byte[blockSize];
System.arraycopy(iv_and_encryptedMessage, 0, ivBytes, 0, blockSize);
return ivBytes;
}
public byte[] extractEncryptedMessageFrom(byte[] iv_and_encryptedMessage, int blockSize) {
byte[] encryptedTextBytes = new byte[iv_and_encryptedMessage.length - blockSize];
System.arraycopy(iv_and_encryptedMessage, blockSize, encryptedTextBytes, 0, encryptedTextBytes.length);
return encryptedTextBytes;
}
}发布于 2016-11-04 23:40:18
我不会说任何关于密码学方面的东西(在我看来,我所看到的看起来还不错(但我也不是专家,请把它带到it安全处,或者实际上付钱给某人),但是除了HSM这将被用来做什么之外,没有任何指示)。
readKeyFile和createKeyFile都被排除在外了。extractIvFrom和extractEncryptedMessageFrom方法,看看GCMParameterSpec的其他构造函数和doFinal的其他方法,它们允许指定要使用的数组部分的偏移量和长度。控制事物也是有点浪费,但我想,对必要的缓冲区大小进行预先计算暂时是可以的。Charset值,或者更好地使用java.nio.charset.StandardCharsets.UTF_8。String,因为这在传递什么方面非常有限,但是如果这是用例,当然。finals,这与没有其他任何标记为final的事实不一致。https://codereview.stackexchange.com/questions/143073
复制相似问题