简体   繁体   English

使用AES和Base64编码进行加密和解密

[英]Encrypt and decrypt with AES and Base64 encoding

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?" 并且例外情况说“ 如何在没有填充密码的情况下进行解密?”

Your Order for encrypt: getBytes, encrypt, encode, toString 您的加密订单: getBytes,encrypt,encode,toString
Your Order for decrypt(Wrong*): getBytes, decrypt, decode, toString 您的解密订单(错误*): getBytes,decrypt,decode,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. encrypt为您提供16个字节,编码24个字节,但toString提供106个字节。 Something to do with invalid chars taking up additional space. 与无效字符占用额外空间有关。

Note: Also, you don't need to call generateKey() twice. 注意:此外,您不需要两次调用generateKey()

Fix problem #1 by using the reverse order for decryption. 通过使用相反的解释顺序修复问题#1
Correct order for decrypt: getBytes, decode, decrypt, toString 正确的解密顺序: getBytes,decode,decrypt,toString

Fix problem #2 by replacing xxx.toString() with new String(xxx) . 通过用new String(xxx)替换xxx.toString() 修复问题#2 Do this in both the encrypt and decrypt functions. 在加密和解密功能中执行此操作。

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”

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. encryptedByteValue的类型是byte [],并且在它上面调用toString不是你想要做的。 Instead try 而是试试

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

Then use Base64.decodeBase64(encryptedValue) in decrypt. 然后在解密时使用Base64.decodeBase64(encryptedValue) You must do that prior to attempting to decrypt though. 您必须在尝试解密之前执行此操作。 You must undo the operations in the reverse order of the encrypt method. 您必须按加密方法的相反顺序撤消操作。

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. 我不认为这是做事的“正确”方式,但找不到文档所说的方法。

I have replaces line in example: 我已经替换了示例中的行:

String encryptedValue = encryptedByteValue.toString();

with next one: 下一个:

String encryptedValue = new String(encryptedByteValue);

All works fine! 一切正常!

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));
}
}

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.Base64 you 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM