Java 使用 AES 和 Base64 编码加密和解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3954611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 07:31:31  来源:igfitidea点击:

Encrypt and decrypt with AES and Base64 encoding

javaencryptionaes

提问by Harshana

I have following program for encrypting data.

我有以下用于加密数据的程序。

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

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

public class Test {

    private static final String ALGORITHM = "AES";
    private static final byte[] keyValue = "ADBSJHJS12547896".getBytes();

    public static void main(String args[]) throws Exception {
        String encriptValue = encrypt("dude5");
        decrypt(encriptValue);

    }

    /**
     * @param args
     * @throws Exception
     */

    public static String encrypt(String valueToEnc) throws Exception {

        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.ENCRYPT_MODE, key);

        System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length);
        byte[] encValue = c.doFinal(valueToEnc.getBytes());
        System.out.println("encValue length" + encValue.length);
        byte[] encryptedByteValue = new Base64().encode(encValue);
        String encryptedValue = encryptedByteValue.toString();
        System.out.println("encryptedValue " + encryptedValue);

        return encryptedValue;
    }

    public static String decrypt(String encryptedValue) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, key);

        byte[] enctVal = c.doFinal(encryptedValue.getBytes());
        System.out.println("enctVal length " + enctVal.length);

        byte[] decordedValue = new Base64().decode(enctVal);

        return decordedValue.toString();
    }

    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGORITHM);
        return key;
    }

}

Here I am getting the following out put with exception?

在这里,我得到以下内容,但有例外?

valueToEnc.getBytes().length 5
encValue length16
encryptedValue [B@aa9835
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)

Can some one explain me the cause? Why its only saying when decrypting that length should be 16. Doesn't it convert to 16 as like encrypting with the doFinal method.

有人可以向我解释原因吗?为什么它在解密时只说长度应该是 16。它不会像使用 doFinal 方法加密一样转换为 16。

And as the exception says "how to decrypting without padded cipher?"

正如例外所说“如何在没有填充密码的情况下解密?”

采纳答案by Babu Srinivasan

Your Order for encrypt:getBytes, encrypt, encode, toString
Your Order for decrypt(Wrong*):getBytes, decrypt, decode, toString

您的加密命令:getBytes、加密、编码、toString
您的解密命令(错误*):getBytes、解密、解码、toString

Two problems:

两个问题:

  1. As someone already mentioned you should reverse the order of operations for decryption. You are not doing that.
  2. encrypt gives you 16 bytes, encode 24 bytes, but toString gives 106 bytes. Something to do with invalid chars taking up additional space.
  1. 正如有人已经提到的,您应该颠倒解密的操作顺序。你不是在这样做。
  2. encrypt 给你 16 个字节,编码 24 个字节,但 toString 给你 106 个字节。与占用额外空间的无效字符有关。

Note: Also, you don't need to call generateKey()twice.

注意:另外,您不需要调用generateKey()两次。

Fix problem #1by using the reverse order for decryption.
Correct order for decrypt:getBytes, decode, decrypt, toString

通过使用相反的解密顺序来解决问题 #1
正确的解密顺序:getBytes、decode、decrypt、toString

Fix problem #2by replacing xxx.toString()with new String(xxx). Do this in both the encrypt and decrypt functions.

修复问题#2通过更换xxx.toString()new String(xxx)。在加密和解密函数中执行此操作。

Your decrypt should look like this:

您的解密应如下所示:

c.init(Cipher.DECRYPT_MODE, key)
val decodedValue = new Base64().decode(encryptedValue.getBytes())
val decryptedVal = c.doFinal(decodedValue)
return new String(decryptedVal)

This should give you back "dude5"

这应该给你回“dude5”

回答by CB Bailey

Fundamentally, there is an asymmetry between your encrypt function and your decrypt function. When you encrypt you perform an AES encrypt and then a base64 encode, when you decrypt you don't first undo the base64 encoding step.

从根本上说,您的加密函数和解密函数之间存在不对称性。加密时先执行 AES 加密,然后再执行 base64 编码,解密时不会先撤消 base64 编码步骤。

I think that there's something wrong with your base64 encoding as well as [shouldn't appear in a base64 encoded string.

我认为你的 base64 编码有问题,[不应该出现在 base64 编码的字符串中。

Looking at the documentation for org.apache.commons.codec.binary.Base64you should be able to do this on encode:

查看org.apache.commons.codec.binary.Base64您的文档应该能够在编码上做到这一点:

String encryptedValue = Base64.encodeBase64String(encValue);

and this on decode:

这在解码上:

byte[] encValue = Base64.decodeBase64(encryptedValue);

回答by laz

The line

线

String encryptedValue = encryptedByteValue.toString();

is the problem. The type of encryptedByteValue is byte[] and calling toString on it isn't what you want to do there. Instead try

是问题所在。encryptedByteValue 的类型是 byte[] 并且在它上面调用 toString 不是你想要在那里做的。而是尝试

String encryptedValue = Base64.getEncoder().encodeToString(encValue);

Then use Base64.decodeBase64(encryptedValue)in decrypt. You must do that prior to attempting to decrypt though. You must undo the operations in the reverse order of the encrypt method.

然后Base64.decodeBase64(encryptedValue)在解密中使用。不过,您必须在尝试解密之前执行此操作。您必须以与加密方法相反的顺序撤消操作。

回答by John Wooten

Where are you getting a version of apache codec that has encodeToString or encodeBase64String?

您从哪里获得具有 encodeToString 或 encodeBase64String 的 apache 编解码器版本?

I downloaded 1.5 from the apache site and while it says in the documentation that these methods exist, they don't show up when you do code completion and they create an unknown method when you provide them.

我从 apache 站点下载了 1.5,虽然它在文档中说这些方法存在,但在您执行代码完成时它们不会出现,并且在您提供它们时它们会创建一个未知的方法。

I was able to do:

我能够做到:

byte raw[] = md.digest(); //step 4
byte hashBytes[] = Base64.encodeBase64(raw); //step 5
StringBuffer buffer = new StringBuffer();
for( int i=0; i<hashBytes.length; i++ )
    buffer.append(hashBytes[i]);
return buffer.toString(); //step 6

And then the string that I obtained was very long, BUT it decrypted correctly.

然后我获得的字符串很长,但它解密正确。

I don't think this is the "right" way to do things, but can't find the methods that the documentation says are there.

我不认为这是做事的“正确”方式,但找不到文档所说的方法。

回答by Alex

I have replaces line in example:

我在示例中替换了行:

String encryptedValue = encryptedByteValue.toString();

with next one:

下一个:

String encryptedValue = new String(encryptedByteValue);

All works fine!

一切正常!

回答by Danyal Sandeelo

That was alright, you just needed to

没关系,你只需要

1) Use new String instead of toString() since toString() doesn't return what you need here (in both cases, encryption and decryption)

1) 使用 new String 而不是 toString() 因为 toString() 不会在这里返回您需要的内容(在这两种情况下,加密和解密)

2) you need to decode first since the value is encode in base64.

2)您需要先解码,因为该值是在 base64 中编码的。

I came across this thread but it took sometime to find out the actual point..I am posting my code for rest of the people who come across this issue.

我遇到了这个线程,但花了一些时间才找出真正的要点……我正在为遇到此问题的其他人发布我的代码。

public abstract class EncryptionDecryption {
static  byte[]  key = "!@#$!@#$%^&**&^%".getBytes();
final static String algorithm="AES";

public static String encrypt(String data){

    byte[] dataToSend = data.getBytes();
    Cipher c = null;
    try {
        c = Cipher.getInstance(algorithm);
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    SecretKeySpec k =  new SecretKeySpec(key, algorithm);
    try {
        c.init(Cipher.ENCRYPT_MODE, k);
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    byte[] encryptedData = "".getBytes();
    try {
        encryptedData = c.doFinal(dataToSend);
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    byte[] encryptedByteValue =    new Base64().encode(encryptedData);
    return  new String(encryptedByteValue);//.toString();
}

public static String decrypt(String data){

    byte[] encryptedData  = new Base64().decode(data);
    Cipher c = null;
    try {
        c = Cipher.getInstance(algorithm);
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    SecretKeySpec k =
            new SecretKeySpec(key, algorithm);
    try {
        c.init(Cipher.DECRYPT_MODE, k);
    } catch (InvalidKeyException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    byte[] decrypted = null;
    try {
        decrypted = c.doFinal(encryptedData);
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return new String(decrypted);
}

public static void main(String[] args){
    String password=EncryptionDecryption.encrypt("password123");
    System.out.println(password);
    System.out.println(EncryptionDecryption.decrypt(password));
}
}