当前位置: 首页 > 知识库问答 >
问题:

如何使用java解码openssl Aes-128-cbc编码的字符串?

洪和平
2023-03-14

我使用openssl使用以下命令对字符串进行编码:

openssl enc -aes-128-cbc -a -salt -pass pass:mypassword <<< "stackoverflow"

结果给我一个编码字符串:U2FsdGVkX187CGv6DbEpqh/L6XRKON7uBGluIU0nT3w=

到目前为止,我只需要使用openssl对其进行解码,因此以下命令将返回先前编码的字符串:

 openssl enc -aes-128-cbc -a -salt -pass pass:mypassword -d <<< "U2FsdGVkX187CGv6DbEpqh/L6XRKON7uBGluIU0nT3w="

结果:stackoverflow

现在,我需要解码编码字符串在一个java应用程序。

有人能给我提供一个简单的java类来解码用前面给定的openssl命令编码的字符串吗?

非常感谢。

共有2个答案

晏卓君
2023-03-14

默认情况下,openssl enc使用(适度地)非标准的基于密码的加密算法和自定义但简单的数据格式。

  1. 如果你真的不需要PBE,只需要一些openssl加密,@Artjom链接的问题有一个很好的答案:在openssl中使用“原始”密钥和IV,然后在Java中使用相同的密钥和IV。让它们都默认为PKCS5(实际上是PKCS#7)填充。请注意,openssl enc在十六进制中同时接受-K-iv,而Java加密将它们作为字节;根据需要进行转换。因为/如果你对密文进行了64-处理,那么首先去64-处理;这是在java8中提供的,并且有许多库可用于早期的java版本。

否则需要解压文件格式。de-bas64后,丢弃前8个字节,取下8个字节作为盐,其余字节作为密文。

如果您需要特定算法AES128-CBC或192或256的PBE,您可以使用第三方加密库,即http://www.BouncyCastle.org,它为这三种算法实现了openssl PBE。为pbewithmd5和128位aes-CBC-OPENSSL或192或256实例SecretKeyFactory,但仅在安装了无限强度策略(更新:或Oracle版本)的情况下

否则你必须自己做PBE。幸运的(?)这很简单。在方便的地方使用以下方法:

public static/*或视情况而定*/void opensslBytesToKey(byte[]pass,byte[]salt/*或null*/,//输入int iter,字符串hashname,//PBKDF1 ish byte[]key,byte[]iv/*或null*///输出)抛出NoSuchAlgorithmException{MessageDigest md=MessageDigest.getInstance(hashname);byte[]temp=null,out=new byte[key.length(iv!=空?iv.长度:0)];int-outidx=0;while(outidx)

并使用密码字节、salt、迭代计数1、“MD5”和输出数组调用它,这些数组的大小与AES密钥(16、24或32字节)和AES IV(始终为16字节)的大小相同。分别在SecretKeySpecIvParameterSpec中与Cipher一起用于(纠正)AES/CBC/PKCS5Padding

旁白:不能加密字符串本身,只能加密字节(或者更确切地说是八位字节)。几乎所有系统上的C程序(包括openssl)都会隐式地将ASCII中的字符串/字符转换为字节或从字节转换为字符串/字符,但使用ASCII集合之外的任何字符都可能产生不一致和不可用的结果。Java将字符串/字符视为Unicode(或者更确切地说是UTF-16),并主要显式地将它们转换为字节和字节;这种转换对于ASCII是可靠的(并且与C一致),但对于非ASCII字符可能会有所不同。

更新:OpenSSL 1.1。0(2016-08)将encPBE的默认哈希值从MD5更改为SHA256。根据用于加密的OpenSSL版本,或者是否使用了(以前未记录的)-md选项,更改my option 3中的调用。有关更多详细信息,请参阅(my)https://crypto.stackexchange.com/questions/3298/is-there-a-standard-for-openssl-interoperable-aes-encryption/#35614

麹承
2023-03-14

使用Bouncy Castle库解决了它。

代码如下:

package example;
import java.util.Arrays;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.BlockCipherPadding;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;

public class OpenSSLAesDecrypter
{
    private static final int AES_NIVBITS = 128; // CBC Initialization Vector (same as cipher block size) [16 bytes]

    private final int keyLenBits;

    public OpenSSLAesDecrypter(int nKeyBits)
    {
        this.keyLenBits = nKeyBits;
    }

    public byte[] decipher(byte[] pwd, byte[] src)
    {
        // openssl non-standard extension: salt embedded at start of encrypted file
        byte[] salt = Arrays.copyOfRange(src, 8, 16); // 0..7 is "SALTED__", 8..15 is the salt

        try
        {
            // Encryption algorithm. Note that the "strength" (bitsize) is controlled by the key object that is used.
            // Note that PKCS5 padding and PKCS7 padding are identical.
            BlockCipherPadding padding = new PKCS7Padding();
            BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), padding);

            CipherParameters params = getCipherParameters(pwd, salt);
            cipher.reset();
            cipher.init(false, params);

            int buflen = cipher.getOutputSize(src.length - 16);
            byte[] workingBuffer = new byte[buflen];
            int len = cipher.processBytes(src, 16, src.length - 16, workingBuffer, 0);
            len += cipher.doFinal(workingBuffer, len);

            // Note that getOutputSize returns a number which includes space for "padding" bytes to be stored in.
            // However we don't want these padding bytes; the "len" variable contains the length of the *real* data
            // (which is always less than the return value of getOutputSize.
            byte[] bytesDec = new byte[len];
            System.arraycopy(workingBuffer, 0, bytesDec, 0, len);
            return bytesDec;
        }
        catch (InvalidCipherTextException e)
        {
            System.err.println("Error: Decryption failed");
            return null;
        }
        catch (RuntimeException e)
        {
            System.err.println("Error: Decryption failed");
            return null;
        }
    }

    private CipherParameters getCipherParameters(byte[] pwd, byte[] salt)
    {
        // Use bouncycastle implementation of openssl non-standard (pwd,salt)->(key,iv) algorithm.
        // Note that if a "CBC" cipher is selected, then an IV is required as well as a key. When using a password,
        // Openssl
        // *derives* the IV from the (pwd,salt) pair at the same time as it derives the key.
        //
        // * PBE = Password Based Encryption
        // * CBC = Cipher Block Chaining (ie IV is needed)
        //
        // Note also that when the IV is derived from (pwd, salt) the salt **must** be different for each message; this is
        // the default for openssl - just make sure to NOT explicitly provide a salt, or encryption security is badly
        // affected.
        OpenSSLPBEParametersGenerator gen = new OpenSSLPBEParametersGenerator();
        gen.init(pwd, salt);
        CipherParameters cp = gen.generateDerivedParameters(keyLenBits, AES_NIVBITS);
        return cp;
    }

    public static void main(String[] args)
    {
        OpenSSLAesDecrypter d = new OpenSSLAesDecrypter(128);
        String r = new String(d.decipher("mypassword".getBytes(),
                Base64.decodeBase64("U2FsdGVkX187CGv6DbEpqh/L6XRKON7uBGluIU0nT3w=")));
        System.out.println(r);
    }
}

使用以下依赖项编译/运行它:

  • apache通用编解码器
 类似资料:
  • 我有一个用mvn Exec:java运行的程序(我的主文件是用utf-8编码的,系统的默认字符集是windows-1252) 我不明白为什么第一次打印工作,根据文档getBytes使用给定的字符集将字符串编码成字节序列,字符串构造函数通过使用平台的默认字符集解码指定的字节数组来构造新的字符串

  • 问题内容: 我得到了一个像这样的字符串 我该如何编写Java代码来解码编码字符,例如 在字符串中。是否有任何现有的类/方法可以对其进行解码? 谢谢。 问题答案: 要取消转义HTML / XML实体,请使用Apache Commons Lang 或homegrow one 。

  • 问题内容: ’=?KOI8-R?B?W1JFUS0wMDI1NDEtNDc5NzddIO / h7yAi89TSz8rGwdLGz9IiIDs =?= \ r \ n \ t =?KOI8-R?B?Ry43MjkgKDEwKQ ==?=’ 如何将其转换为可读的内容?谢谢 ! 问题答案: email.header.decode_header(‘=?KOI8-R?B?W1JFUS0wMDI1NDEtN

  • 本文向大家介绍如何在JavaScript中解码编码的字符串?,包括了如何在JavaScript中解码编码的字符串?的使用技巧和注意事项,需要的朋友参考一下 解码 在JavaScript中,使用unescape()方法解码字符串。该方法采用一个字符串,该字符串由escape()方法编码,并对其进行解码。字符串中的十六进制字符将被使用unescape()方法表示的实际字符替换。 语法 示例 接下来,两

  • 问题内容: 我需要在GWT中将短字符串编码为base 64,并在服务器上解码base 64字符串。有人为此有实用程序类或库吗? 问题答案: 您可以在除IE≤9之外的所有浏览器上的客户端上使用本机JavaScript,在服务器上可以使用官方类之一。 Java / GWT: 编码为。

  • 问题内容: 我有一个像这样的字符串: 我想加密要在干净URL中使用的字符串A。像这样的东西: 给定字符串A,python中是否有编码API,它返回字符串B?给定字符串B,python中是否有解码API,它返回字符串A? 问题答案: 进行编码/解码的一种方法是使用包base64,例如: 是您要找的东西吗?对于您的特殊情况,您将获得: 输入:12234_1_Hello’World_34433_22ac