Шифрование Java AES с использованием CBC и PKCS7Padding - PullRequest
0 голосов
/ 04 ноября 2018

Я боролся с этим уже пару дней. Мне нужно использовать 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) Использование надувного замка для использования 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;
    }
}

1 Ответ

0 голосов
/ 04 ноября 2018

Java Пакет шифров поддерживает только заполнение PKCS # 7; AES/CBC/PKCS5Padding. Используйте это;

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

№ 5 и № 7 являются взаимозаменяемыми для большинства блочных шифров. Смотрите вопрос на Crypto.StackExchange

и, для использования AES с 256-битным размером ключа;

Стандартная библиотека шифров Java ограничена размером ключа 128 бит. Вы должны пойти и загрузить файлы политики неограниченной юрисдикции Java Cryptography Extension (JCE) 6

...