Member 14205873 Ответов: 0

Как я могу зашифровать сообщение паролем в java, аналогично команде openssl enc -aes-256-cbc -a -salt ?


Привет, у меня есть следующий код для расшифровки, похожий на openssl. Я ищу java-код для шифрования, который имитирует openssl-aes-256-cbc -a -salt с заданной строкой и паролем. Любая подсказка/помощь приветствуется.

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class AES5 {

    private static final Charset ASCII = Charset.forName("ASCII");
    private static final int INDEX_KEY = 0;
    private static final int INDEX_IV = 1;
    private static final int ITERATIONS = 1;
    private static final int SALT_OFFSET = 8;
    private static final int SALT_SIZE = 8;
    private static final int CIPHERTEXT_OFFSET = SALT_OFFSET + SALT_SIZE;
    private static final int KEY_SIZE_BITS = 256;

    /**
     * Thanks go to Ola Bini for releasing this source on his blog. The source was
     * obtained from <a href="http://olabini.com/blog/tag/evp_bytestokey/">here</a>
     * 
     */

    public static byte[][] EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data,
            int count) {

        byte[][] both = new byte[2][];
        byte[] key = new byte[key_len];
        int key_ix = 0;
        byte[] iv = new byte[iv_len];
        int iv_ix = 0;
        both[0] = key;
        both[1] = iv;
        byte[] md_buf = null;
        int nkey = key_len;
        int niv = iv_len;
        int i = 0;
        if (data == null) {
            return both;
        }
        int addmd = 0;
        for (;;) {
            md.reset();
            if (addmd++ > 0) {
                md.update(md_buf);
            }
            md.update(data);
            if (null != salt) {
                md.update(salt, 0, 8);
            }
            md_buf = md.digest();
            for (i = 1; i < count; i++) {
                md.reset();
                md.update(md_buf);
                md_buf = md.digest();
            }
            i = 0;
            if (nkey > 0) {
                for (;;) {
                    if (nkey == 0)
                        break;
                    if (i == md_buf.length)
                        break;
                    key[key_ix++] = md_buf[i];
                    nkey--;
                    i++;
                }
            }
            if (niv > 0 && i != md_buf.length) {
                for (;;) {
                    if (niv == 0)
                        break;
                    if (i == md_buf.length)
                        break;
                    iv[iv_ix++] = md_buf[i];
                    niv--;
                    i++;
                }
            }
            if (nkey == 0 && niv == 0) {
                break;
            }
        }
        for (i = 0; i < md_buf.length; i++) {
            md_buf[i] = 0;
        }
        return both;
    }


    public static byte[][] getKeyIV(byte[] headerSaltAndCipherText, Cipher aesCBC, String password) {       
        byte[] salt = Arrays.copyOfRange(headerSaltAndCipherText, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
        byte[][] keyAndIV=null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            keyAndIV = EVP_BytesToKey(KEY_SIZE_BITS / Byte.SIZE, aesCBC.getBlockSize(), md5, salt,
                    password.getBytes(ASCII), ITERATIONS);
        } catch (Exception e) {e.printStackTrace();}

        return keyAndIV;
    }

    // https://stackoverflow.com/questions/11783062/how-to-decrypt-file-in-java-encrypted-with-openssl-command-using-aes
    public static String decrypt(String encryptedMsg, String password) {

        String decryptedMsg =null;      
        byte[] headerSaltAndCipherText = Base64.decodeBase64(encryptedMsg);
        byte[] encrypted = Arrays.copyOfRange(headerSaltAndCipherText, CIPHERTEXT_OFFSET, headerSaltAndCipherText.length);
        try {
            Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
            final byte[][] keyAndIV = getKeyIV(headerSaltAndCipherText, aesCBC, password);
            SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
            IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
            aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] decrypted = aesCBC.doFinal(encrypted);
            decryptedMsg = new String(decrypted, ASCII);
        } catch (Exception e) {e.printStackTrace();}

        return decryptedMsg;
    }

    public static void main(String[] args) {

        String msg = "the decrypted message is this";
        String password = "pass";

        System.out.println(encrypt(msg, password));

        String encryptedMsg = "U2FsdGVkX190A5FsNTanwTKBdex29SpnH4zWkZN+Ld+MmbJgK4BH1whGIRRSpOJT";
        System.out.println(decrypt(encryptedMsg, password));
    }
}


Что я уже пробовал:

I have the following function for encryption, but its not giving the expected output..

<pre>public static String encrypt(String msg, String password) {

    String encryptedMsg =null;      
    byte[] headerSaltAndCipherText = Base64.decodeBase64(msg);      
    try {
        Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final byte[][] keyAndIV = getKeyIV(headerSaltAndCipherText, aesCBC, password);
        SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
        IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
        aesCBC.init(Cipher.ENCRYPT_MODE, key, iv);
        encryptedMsg = Base64.encodeBase64String(aesCBC.doFinal(msg.getBytes("UTF-8")));                        
    } catch (Exception e) {e.printStackTrace();}

    return encryptedMsg;
}


Выход:

+uu21LwpQq3IXRfOxpSgF8rrQHfc9owMrha/TnEsv/8=
расшифрованное сообщение таково

Ожидаемая зашифрованная строка =
"U2FsdGVkX190A5FsNTanwTKBdex29Spnh4zwkzn+Ld+MmbJgK4BH1whGIRRSpOJT"

Собственно зашифрованная строка =
"+uu21LwpQq3IXRfOxpSgF8rrQHfc9owMrha/TnEsv/8="

k5054

Вам нужно передать один и тот же пароль и соль, чтобы получить идентичные выходные данные, например

k5054@debian:~$ echo "the encrypted message is this" | openssl enc -aes-256-cbc -a -salt 
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
U2FsdGVkX1+SWiZRzt/w0ZkUz3EjOFTiVtibL9m+gEeyrdtpNap3MNLS/SoWhkKP
k5054@debian:~$ echo "the encrypted message is this" | openssl enc -aes-256-cbc -a -salt 
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
U2FsdGVkX19wGMNxrjGSdAXVw6cDCWTlMc9gGbVIOnf+R4DTZ7vRS7Liabcglpm9
k5054@debian:~$ echo "the encrypted message is this" | openssl enc -aes-256-cbc -a -salt 
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
U2FsdGVkX1/x2Om88MSlWgHtzEuarh8UIMOHo4aA63OA8ruhRbJr4ba6/vPEv1Pr

Далее, предполагая, что ожидаемая строка верна при попытке декодирования, я получаю
k5054@debian:~$ echo "U2FsdGVkX190A5FsNTanwTKBdex29SpnH4zWkZN+Ld+MmbJgK4BH1whGIRRSpOJT" | openssl enc -aes-256-cbc -d -a -salt
enter aes-256-cbc decryption password: [enter pass]
bad decrypt
140066702831680:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:536:
<gibberish removed>k5054@debian:~$ 

поэтому я подозреваю, что вы не используете один и тот же пароль между двумя запусками. Попробуйте использовать openssl enc -a aes-256-cbc -a -S 0102030405060709 -k pass
чтобы сгенерировать ожидаемую зашифрованную строку. Однако еще более неприятным является тот факт, что ваши две струны имеют разную длину.

Member 14205873

Но есть ли идеи, как это сделать на Java, или какая коррекция необходима в функции шифрования ?

Код генерирует "+uu21LwpQq3IXRfOxpSgF8rrQHfc9owMrha/TnEsv/8=" но я ожидал
"U2FsdGVkX190A5FsNTanwTKBdex29Spnh4zwkzn+Ld+MmbJgK4BH1whGIRRSpOJT". Расшифровка работает нормально.

Richard MacCutchan

Это может быть связано с тем, что Java хранит данные в формате big-endian, тогда как по умолчанию для C# используется little endian. Это означает, что преобразование символов в байты не приводит к одинаковым результатам. Видеть Sha 256 в java и C# получают разные значения[^].

0 Ответов