首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java AES/CBC解密后初始字节不正确

Java AES/CBC解密后初始字节不正确
EN

Stack Overflow用户
提问于 2013-03-22 01:31:51
回答 10查看 479.5K关注 0票数 117

下面的例子有什么问题?

问题是,解密字符串的第一部分是无意义的。但是,其他的都很好,我得到了...

结果:‘�eB6O�geS��I are you?祝您今天愉快。

代码语言:javascript
复制
@Test
public void testEncrypt() {
  try {
    String s = "Hello there. How are you? Have a nice day.";

    // Generate key
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128);
    SecretKey aesKey = kgen.generateKey();

    // Encrypt cipher
    Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);

    // Encrypt
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptCipher);
    cipherOutputStream.write(s.getBytes());
    cipherOutputStream.flush();
    cipherOutputStream.close();
    byte[] encryptedBytes = outputStream.toByteArray();

    // Decrypt cipher
    Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
    decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);

    // Decrypt
    outputStream = new ByteArrayOutputStream();
    ByteArrayInputStream inStream = new ByteArrayInputStream(encryptedBytes);
    CipherInputStream cipherInputStream = new CipherInputStream(inStream, decryptCipher);
    byte[] buf = new byte[1024];
    int bytesRead;
    while ((bytesRead = cipherInputStream.read(buf)) >= 0) {
        outputStream.write(buf, 0, bytesRead);
    }

    System.out.println("Result: " + new String(outputStream.toByteArray()));

  } 
  catch (Exception ex) {
    ex.printStackTrace();
  }
}
EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2014-03-17 10:17:23

很多人,包括我自己,由于遗漏了一些信息,比如忘记转换成Base64,初始化向量,字符集等,所以我想做一个功能齐全的代码。

希望这篇文章能对大家有所帮助:要编译,您需要额外的Apache Commons Codec jar,可以在这里找到:http://commons.apache.org/proper/commons-codec/download_codec.cgi

代码语言:javascript
复制
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class Encryptor {
    public static String encrypt(String key, String initVector, String value) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string: "
                    + Base64.encodeBase64String(encrypted));

            return Base64.encodeBase64String(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static String decrypt(String key, String initVector, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

            byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
        String key = "Bar12345Bar12345"; // 128 bit key
        String initVector = "RandomInitVector"; // 16 bytes IV

        System.out.println(decrypt(key, initVector,
                encrypt(key, initVector, "Hello World")));
    }
}
票数 231
EN

Stack Overflow用户

发布于 2018-10-30 02:23:11

在这个答案中,我选择讨论“简单的Java AES加密/解密示例”这一主题,而不是具体的调试问题,因为我认为这将使大多数读者受益。

这是对我的blog post about AES encryption in Java的一个简单总结,所以我建议在实现任何东西之前先通读一遍。然而,我仍然会提供一个简单的例子来使用,并给出一些需要注意的问题。

在本例中,我将选择在Galois/Counter Mode or GCM模式下使用authenticated encryption。原因是在大多数情况下,您需要integrity and authenticity in combination with confidentiality (在blog中阅读更多)。

AES-GCM加密/解密教程

以下是在Java Cryptography Architecture (JCA)中使用AES-GCM进行加密/解密所需的步骤。不要与其他示例混合在一起,因为细微的差异可能会使您的代码完全不安全。

1.创建密钥

因为它取决于您的用例,所以我将假定最简单的情况:随机密钥。

代码语言:javascript
复制
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");

重要信息:

2.创建初始化向量

使用initialization vector (IV)使得相同的密钥将创建不同的cipher texts

代码语言:javascript
复制
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);

重要信息:

  • 从不使用相同的密钥( GCM/CTR
  • the IV中非常重要的必须是唯一的(即使用随机IV或计数器)字节IV不需要为secret
  • always使用像SecureRandom
  • 12这样的强字节使用choice for AES-GCM mode

IV is

3.使用IV和Key加密

代码语言:javascript
复制
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);

重要信息:

JCA使用16字节/ 128位GCM (用于验证integrity/authenticity)

  • the身份验证标签是否会自动附加到密文中)(在
  • 中,authentication tag的行为类似于流密码,无需填充
  • 在加密大块数据时使用CipherInputStream
  • 是否要检查附加(非机密)数据是否已更改?您可能希望在cipher.updateAAD(associatedData); More here.

中使用associated data

3.序列化到单个消息

只需添加IV和密文即可。如上所述,静脉注射不需要保密。

代码语言:javascript
复制
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();

如果需要字符串表示,可以选择使用Base64进行编码。使用Android'sJava 8's built-in实现(不要使用Apache Commons Codec -这是一个糟糕的实现)。编码用于将字节数组“转换”为字符串表示,以使其ASCII安全,例如:

代码语言:javascript
复制
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);

4.准备解密:反序列化

如果您已经对消息进行了编码,请先将其解码为字节数组:

代码语言:javascript
复制
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)

重要信息:

5.解密

初始化密码,并设置与加密相同的参数:

代码语言:javascript
复制
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
//use first 12 bytes for iv
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
//use everything from 12 bytes on as ciphertext
byte[] plainText = cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12);

重要信息:

如果您在encryption.期间添加了

  • ,请不要忘记使用associated data添加cipher.updateAAD(associatedData);

A working code snippet can be found in this gist.

请注意,最新的Android (SDK )和Java (7+)实现应该具有21+-GCM。较旧的版本可能缺少此功能。我仍然选择这种模式,因为与类似的Encrypt-then-Mac模式(例如AES-CBC )相比,它更容易实现,而且效率更高。See this article on how to implement AES-CBC with HMAC

票数 83
EN

Stack Overflow用户

发布于 2015-04-03 02:21:28

这里是一个没有Apache Commons CodecBase64的解决方案

代码语言:javascript
复制
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AdvancedEncryptionStandard
{
    private byte[] key;

    private static final String ALGORITHM = "AES";

    public AdvancedEncryptionStandard(byte[] key)
    {
        this.key = key;
    }

    /**
     * Encrypts the given plain text
     *
     * @param plainText The plain text to encrypt
     */
    public byte[] encrypt(byte[] plainText) throws Exception
    {
        SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        return cipher.doFinal(plainText);
    }

    /**
     * Decrypts the given byte array
     *
     * @param cipherText The data to decrypt
     */
    public byte[] decrypt(byte[] cipherText) throws Exception
    {
        SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        return cipher.doFinal(cipherText);
    }
}

使用示例:

代码语言:javascript
复制
byte[] encryptionKey = "MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8);
byte[] plainText = "Hello world!".getBytes(StandardCharsets.UTF_8);
AdvancedEncryptionStandard advancedEncryptionStandard = new AdvancedEncryptionStandard(
        encryptionKey);
byte[] cipherText = advancedEncryptionStandard.encrypt(plainText);
byte[] decryptedCipherText = advancedEncryptionStandard.decrypt(cipherText);

System.out.println(new String(plainText));
System.out.println(new String(cipherText));
System.out.println(new String(decryptedCipherText));

打印:

代码语言:javascript
复制
Hello world!
դ;��LA+�ߙb*
Hello world!
票数 38
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15554296

复制
相关文章

相似问题

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