首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于javax.crypto的对称解密

基于javax.crypto的对称解密
EN

Code Review用户
提问于 2017-01-12 15:00:37
回答 1查看 58关注 0票数 3

我试图确定这段代码是否会占用大量文件的内存。有人能告诉我,我是否可以做些什么来提高内存的效率,或者java.crypto就是这样工作的?

代码语言:javascript
复制
private byte[] symmetricDecryptAttachment(byte[] encryptedAttachmentBytes, byte[] keyBytes) throws IOException, GeneralSecurityException, EIPException {
    byte[] decryptedValue = null;

    // TODO: change to use non-deprecated method ConfigurationManager:getParsedStringValue() instead of getStringValue() which is deprecated
    String decryptionAlgorithm = manager.getStringValue(SymmetricDecryptionAlgorithm);
    String cipherBlockMode = manager.getStringValue(SymmetricDecryptionBlockCipherMode);
    String padding = manager.getStringValue(SymmetricDecryptionPadding);

    // Key bytes are only the first 16 bytes
    final int KEY_BYTES_STARTING_BYTE = 0;
    final int KEY_BYTES_ENDING_BYTE = 16;

    // IV bytes are only the first 16 bytes
    final int IV_BYTES_STARTING_BYTE = 0;
    final int IV_BYTES_ENDING_BYTE = 16;

    // Cipher bytes are everything after first 16 bytes (iv bytes)
    final int CIPHER_BYTES_STARTING_BYTE = IV_BYTES_ENDING_BYTE;

    try {
        // 1. Get the cipher ready to start doing the AES transformation
        Cipher cipher = Cipher.getInstance(decryptionAlgorithm + "/" + cipherBlockMode + "/" + padding);

        // 2. Only take the first 16 bytes so that it is 128 bits as we are doing AES 128 bit decryption
        //      *Note: if this is not 128 bit decryption then you might have to change this ...
        byte[] trimmedKeyBytes = Arrays.copyOfRange(keyBytes, KEY_BYTES_STARTING_BYTE, KEY_BYTES_ENDING_BYTE);

        // 3. Start the decryption process by creating a key spec object
        SecretKeySpec keySpec = new SecretKeySpec(trimmedKeyBytes, decryptionAlgorithm);

        // 4. The initialization vector (IV) is the first 16 bytes/octets of the cipher value in the body.
        // 4.1 To recover the IV, Base64 decode the CipherValue
        byte[] cipherBytes = Base64.decodeBase64(encryptedAttachmentBytes);

        // 4.2 The remainder after the first 16 bytes is the encrypted message
        //      -do +2 from start because we want to remove \r\n at the beginning and -2 to remove \r\n from the end
        // Remove the new line and carriage returns from beginning and end, if they are there
        byte[] encryptedBytes = null;
        byte[] ivBytes = null;
        if( encryptedAttachmentBytes[0] == '\r' &&
                encryptedAttachmentBytes[1] == '\n' &&
                encryptedAttachmentBytes[encryptedAttachmentBytes.length-2] == '\r' &&
                encryptedAttachmentBytes[encryptedAttachmentBytes.length-1] == '\n') {
            encryptedBytes = Arrays.copyOfRange(encryptedAttachmentBytes, CIPHER_BYTES_STARTING_BYTE + 2, encryptedAttachmentBytes.length - 2);

            // 4.2a And take bytes 2 thru 18 instead of 0 thru 16 to account for extra \r \n's
            ivBytes = Arrays.copyOfRange(encryptedAttachmentBytes, IV_BYTES_STARTING_BYTE + 2, IV_BYTES_ENDING_BYTE + 2);
        }else{
            encryptedBytes = Arrays.copyOfRange(encryptedAttachmentBytes, CIPHER_BYTES_STARTING_BYTE, encryptedAttachmentBytes.length);

            // 4.2b And take the first 16 bytes from encrypted text to get the IV bytes
            ivBytes = Arrays.copyOfRange(encryptedAttachmentBytes, IV_BYTES_STARTING_BYTE, IV_BYTES_ENDING_BYTE);
        }

        // 5. Create the IV Parameter spec from the ivBytes obtained above
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        // 6. Initialize the cipher using the key spec and iv we just initialized
        cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

        // 7. Finish the decryption process
        decryptedValue = cipher.doFinal(encryptedBytes);
    } catch (Exception e) {
        System.err.println("Exception occurred in symmetricDecryptAttachment() of SOAPDecryptionProcessor: \n" + e.getMessage());
        throw new EIPException(e.getMessage());
    }

    return decryptedValue;
}
EN

回答 1

Code Review用户

发布于 2020-03-04 01:09:48

代码语言:javascript
复制
String decryptionAlgorithm = manager.getStringValue(SymmetricDecryptionAlgorithm);

这是什么管理器,为什么方法必须执行自己的配置?

代码语言:javascript
复制
// Key bytes are only the first 16 bytes
final int KEY_BYTES_STARTING_BYTE = 0;
final int KEY_BYTES_ENDING_BYTE = 16;

final int IV_BYTES_STARTING_BYTE = 0;
final int IV_BYTES_ENDING_BYTE = 16;

完全不需要,如果它们是,它们应该是private static类变量,这是Java常量的等价物。那么使用Cipher#getBlockSize()呢?

代码语言:javascript
复制
// 1. Get the cipher ready to start doing the AES transformation
Cipher cipher = Cipher.getInstance(decryptionAlgorithm + "/" + cipherBlockMode + "/" + padding);

这个注释是危险的,因为它提到了AES,但是您配置了decryptionAlgorithm。我不知道为什么为此需要3个单独的配置字段。

代码语言:javascript
复制
byte[] trimmedKeyBytes = Arrays.copyOfRange(keyBytes, KEY_BYTES_STARTING_BYTE, KEY_BYTES_ENDING_BYTE);

那么,如果用户提供了一个256位的密钥,那么只需使用128位而不抛出错误?这根本不是什么好做法。

代码语言:javascript
复制
byte[] encryptedBytes = null;
byte[] ivBytes = null;

您已经在if语句中分配引用,无需将它们初始化为null。您甚至可以将它们设置为final,以便您知道每个分支都将初始化变量!

代码语言:javascript
复制
//      -do +2 from start because we want to remove \r\n at the beginning and -2 to remove \r\n from the end
// Remove the new line and carriage returns from beginning and end, if they are there

您有二进制数据,它已经被64位解码,而您原来的二进制密文可能包含一个回车+行提要?嗯,随机的IV或密文可能包含的概率为1/65536,这意味着你的解密将失败约40亿次。你只需要等待足够长的时间才能实现。

代码语言:javascript
复制
encryptedBytes = Arrays.copyOfRange(encryptedAttachmentBytes, CIPHER_BYTES_STARTING_BYTE, encryptedAttachmentBytes.length);

首先,我不知道你为什么要复制加密的数据,然后是IV字节,因为这根本就没有意义--你从来没有按照这个顺序接收或需要它们。

但是请注意,IvParameterSpec()构造函数和Cipher#doFinal()方法都有表单,允许您定义偏移量和要使用的字节数。对于IV来说,这并不重要,但对于密文来说,这又增加了伤害。

代码语言:javascript
复制
private byte[] symmetricDecryptAttachment(byte[] encryptedAttachmentBytes, byte[] keyBytes) throws IOException, GeneralSecurityException, EIPException {
    try {
        ...
    } catch (Exception e) {
        System.err.println("Exception occurred in symmetricDecryptAttachment() of SOAPDecryptionProcessor: \n" + e.getMessage());
        throw new EIPException(e.getMessage());
    }

Pokemon异常处理,使用System.out,从堆栈跟踪中删除异常,不指定可以抛出哪些异常,也不区分不同类型的异常(NoSuchAlgorithmException不同于糟糕的密文,对吗?)

这种异常处理必须进行。

请注意,CBC只对机密性有用,然后最好只对经过身份验证的消息或就地加密/解密有用。我不确定您是否在使用GCM,但是使用GCM可能是一个更好的选择(在一个12字节的IV中)。

至于你的问题:是的,使用流。增量更新也是可能的,但考虑到您的密文可能到达每个流,使用CipherInputStream是最有意义的。注意,Base64编码器类也可以包装在流上。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

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

复制
相关文章

相似问题

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