使用CBC和PKCS7Padding的Java AES加密

使用CBC和PKCS7Padding的Java AES加密,java,encryption,aes,pkcs#7,Java,Encryption,Aes,Pkcs#7,我已经为此挣扎了几天了。我需要使用一个接受加密参数的API。API是用C#编写的。请求的加密如下所示: 算法:AES 密码模式:CBC 填充模式:PKCS7 块大小:128 密钥大小:256 Key:String-->通过将提供的字符串转换为大小为32:Encoding.ASCII.GetBytes(…)的字节数组来生成密钥。API声明字符串是由它们使用字符串的MD5哈希函数生成的 IV:IV数组是通过将提供的字符串转换为大小为16:Encoding.ASCII.GetBytes(…)的字节数

我已经为此挣扎了几天了。我需要使用一个接受加密参数的API。API是用C#编写的。请求的加密如下所示:


算法:AES
密码模式:CBC
填充模式:PKCS7
块大小:128
密钥大小:256

Key:String-->通过将提供的字符串转换为大小为32:Encoding.ASCII.GetBytes(…)的字节数组来生成密钥。API声明字符串是由它们使用字符串的MD5哈希函数生成的

IV:IV数组是通过将提供的字符串转换为大小为16:Encoding.ASCII.GetBytes(…)的字节数组生成的

加密字符串的表示形式:Base64


在搜索和尝试了这么多在线建议的内容之后,我仍然无法生成相同的加密值(特别是默认情况下不支持PKCS7,PKCS5应该是相同的,但它不是)。以下是我尝试过的一些事情:
1) 使用bouncy castle jar来使用PKCS7
2) 添加JCE合规性,以消除对键和块大小的限制

联系他们后,他们向我发送了一个运行正常的android代码段(如果我在纯java 8中运行,会抱怨提供程序(NoSuchAlgorithmException:找不到任何支持AES/CBC/PKCS7Padding的提供程序)):

如果您有任何帮助,我们将不胜感激

以下是我尝试的代码片段:

package com.melhem.TestJava;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class StringFunc {


    final static String key = "API_KEY_32_CHARs";
    final static String iv = "API_IV_16_CHARs";
    final static String algorithm = "AES/CBC/PKCS7Padding";
    private static Cipher cipher = null;
    private static SecretKeySpec skeySpec = null;
    private static IvParameterSpec  ivSpec = null;

    public static void main(String[] args) {
        System.out.println(encrypt("STRING_TO_ENCODE"));
    }

    private static void setUp(){
        try{
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
            skeySpec = new SecretKeySpec(key.getBytes("ASCII"), "AES");
            ivSpec = new IvParameterSpec(iv.getBytes("ASCII"));
            cipher = Cipher.getInstance(algorithm);
        }catch(NoSuchAlgorithmException | NoSuchPaddingException ex){

            ex.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static String encrypt(String str){
        try{
//            Integer strL = (int) Math.ceil(str.length() / 8.0);
//            Integer strB = strL*8;
//            str = padRight(str, ' ', strB);
            setUp();
            try {
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
                System.out.println("Block size: " + cipher.getBlockSize() * 8);
                System.out.println("Algorithm name: " + cipher.getAlgorithm());
                System.out.println("Key size: " + skeySpec.getEncoded().length * 8);
            } catch (InvalidAlgorithmParameterException ex) {
                ex.printStackTrace();
                return "";
            }
            byte[] enc = cipher.doFinal(str.getBytes("ASCII"));
            String s = new String(Base64.getEncoder().encode(enc));
            s = s.replace("+", "__plus__");
            s = s.replace("/", "__slash__");
            return s;
        }catch(InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex){
            ex.printStackTrace();
            return "";            
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return "";
        }
    }

    public static String padRight(String msg, char x, int l) {
        String result = "";
        if (!msg.isEmpty()) {
            for (int i=0; i<(l-msg.length()); i++) {
                result = result + x;
            }
            result = msg + result;
        }
        return result;
    }
}
package com.melhem.TestJava;
导入java.io.UnsupportedEncodingException;
导入java.security.invalidalgorithParameterException;
导入java.security.InvalidKeyException;
导入java.security.NoSuchAlgorithmException;
导入java.security.security;
导入java.util.Base64;
导入javax.crypto.BadPaddingException;
导入javax.crypto.Cipher;
导入javax.crypto.IllegalBlockSizeException;
导入javax.crypto.NoSuchPaddingException;
导入javax.crypto.spec.IvParameterSpec;
导入javax.crypto.spec.SecretKeySpec;
公共类StringFunc{
最终静态字符串key=“API\u key\u 32\u CHARs”;
最终静态字符串iv=“API_iv_16_CHARs”;
最终静态字符串算法=“AES/CBC/PKCS7Padding”;
私有静态密码=null;
私有静态SecretKeySpec skeySpec=null;
私有静态IvParameterSpec ivSpec=null;
公共静态void main(字符串[]args){
System.out.println(加密(“字符串编码”);
}
私有静态无效设置(){
试一试{
addProvider(新org.bouncycastle.jce.provider.BouncyCastleProvider());
skeySpec=newsecretkeyspec(key.getBytes(“ASCII”),“AES”);
ivSpec=新的IvParameterSpec(iv.getBytes(“ASCII”);
cipher=cipher.getInstance(算法);
}捕获(NoSuchAlgorithmException | NoSuchPaddingException ex){
例如printStackTrace();
}捕获(不支持的编码异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
公共静态字符串加密(字符串str){
试一试{
//整数strL=(int)Math.ceil(str.length()/8.0);
//整数strB=strL*8;
//str=padRight(str',,strB);
设置();
试一试{
cipher.init(cipher.ENCRYPT_模式,skeySpec,ivSpec);
System.out.println(“块大小:“+cipher.getBlockSize()*8”);
System.out.println(“算法名称:+cipher.getAlgorithm());
System.out.println(“键大小:+skeySpec.getEncoded().length*8);
}捕获(无效算法参数异常){
例如printStackTrace();
返回“”;
}
byte[]enc=cipher.doFinal(str.getBytes(“ASCII”);
字符串s=新字符串(Base64.getEncoder().encode(enc));
s=s。替换(“+”,“_加上“);
s=s。替换(“/”,“_斜杠”;
返回s;
}捕获(InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex){
例如printStackTrace();
返回“”;
}捕获(不支持的编码异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
返回“”;
}
}
公共静态字符串padRight(字符串msg、字符x、int l){
字符串结果=”;
如果(!msg.isEmpty()){
对于(int i=0;iJava仅支持PKCS#7填充和
AES/CBC/PKCS5Padding
。这不是一个好的命名,因为PKCS#5填充支持8字节的块大小,而DES和PKCS#7最多支持255字节。对于Java,请使用此选项

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
#5和#7对于大多数现代分组密码来说是不可互换的,因为AES是128位分组密码。请参阅上的问题

以及,用于使用256位密钥大小的AES


Java标准密码库限制为128位密钥大小。您必须去下载Java

Thx kelalaka..我尝试过,但它抛出了无效的算法参数异常:错误的IV长度:必须是8字节长..此外,API要求IV的大小为16字节,算法为AES是的,我以前尝试过使用它,因为它们是可互换的它会产生API无法解密的不同值。您认为这是否意味着API所有者在加密后会执行额外的步骤,或者问题是使用PKCS5Padding?我已经从JCE添加了两个JAR,但问题仍然存在。这不是因为它在添加JCE JAR后抱怨密钥大小,而是它提供了错误的值。您忘记了doFi吗nal?如果您使用最新版本的Java 8或更高版本,您不再需要无限强度管辖权策略文件,它们已经包含在内。这里是您问题中缺少的内容:您声称自己尝试过但不起作用的Java代码。好吧,此代码不会产生您声称在其他地方遇到的异常。请仔细阅读。MCVE是解决stackoverflow问题的方法。您的问题与p无关
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");