首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AES加密/解密

AES加密/解密
EN

Code Review用户
提问于 2016-10-03 07:30:18
回答 1查看 342关注 0票数 4

在我目前工作的地方,我的任务是编写一个好的加密和解密代码,它将包含DEK和KEK。还没开始用KEK呢。我已经告诉他们,我们需要专家的帮助,但我不认为我会得到任何帮助。任何关于KEK的提示,如何生成它们,以及在哪里存储它们?(HSM ?)我会很感激的。

经过一周的研究,我写了下面的代码。

寻找关于下面代码中的错误以及如何修复它的反馈。另外,我使用GUID作为身份验证标记,它绑定到信息所属的用户。加密的文本和标记存储在不同位置的单独数据库中。我在正确的道路上吗?如果没有请给我看看。

代码语言:javascript
复制
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;
    }
}
EN

回答 1

Code Review用户

发布于 2016-11-04 23:40:18

我不会说任何关于密码学方面的东西(在我看来,我所看到的看起来还不错(但我也不是专家,请把它带到it安全处,或者实际上付钱给某人),但是除了HSM这将被用来做什么之外,没有任何指示)。

  • 我想readKeyFilecreateKeyFile都被排除在外了。
  • 至少没有必要使用extractIvFromextractEncryptedMessageFrom方法,看看GCMParameterSpec的其他构造函数和doFinal的其他方法,它们允许指定要使用的数组部分的偏移量和长度。控制事物也是有点浪费,但我想,对必要的缓冲区大小进行预先计算暂时是可以的。
  • 有些值被重复使用,只需将它们移动到常量中,比如Charset值,或者更好地使用java.nio.charset.StandardCharsets.UTF_8
  • 就API而言,我可能不会对纯文本使用实际的String,因为这在传递什么方面非常有限,但是如果这是用例,当然。
  • 在方法中存在随机的finals,这与没有其他任何标记为final的事实不一致。
  • 最后,您可能会听到关于单例的不同建议,不过我发现,如果所有内容都指向单个实例,那么测试可能不会有太大帮助。至少它是线程安全的,所以这是有意义的,但这也可以通过静态方法来实现。
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/143073

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档