繁体   English   中英

使用 CBC 和 PKCS7Padding 的 Java AES 加密

[英]Java AES Encryption with CBC and PKCS7Padding

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


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

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

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

加密字符串的表示:Base64


在搜索并尝试了许多在线建议的内容后,我仍然无法生成相同的加密值(特别是默认情况下不支持 PKCS7,而 PKCS5 应该可以正常工作,但事实并非如此)。 以下是我尝试过的一些事情:
1) 使用充气城堡 jar 来使用 PKCS7
2) 添加 JCE 合规性,以消除对密钥和块大小的限制。

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

public static String encrypt(String value) {
        String plainText = value;
        String escapedString;
        try {
            byte[] key = ENCRYPT_KEY.getBytes("UTF-8");
            byte[] ivs = ENCRYPT_IV.getBytes("UTF-8");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivs);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, paramSpec);
            escapedString = Base64.encodeToString(cipher.doFinal(plainText.getBytes("UTF-8")), Base64.DEFAULT).trim();

            return escapedString;
        } catch (Exception e) {
            e.printStackTrace();
            return value;
        }
    }  

请任何帮助将不胜感激。

这是我尝试过的代码片段:

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

Java Cipher 包仅支持使用AES/CBC/PKCS5Padding PKCS#7 填充。 这不是一个好的命名,因为 PKCS#5 填充支持 8 字节的块大小,因为 DES 和 PKCS#7 最多支持 255 字节。 对于 Java 使用这个;

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

#5 和 #7 对于最现代的分组密码不可互换,因为 AES 是 128 位分组密码。 请参阅Crypto.StackExchange上的问题。

并且,用于使用 256 位密钥大小的 AES;

Java 标准密码库限制为 128 位密钥大小。 您必须去下载 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6

暂无
暂无

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

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