java - AES PBE 在 Java 中加密/在 Ruby 中解密

标签 java ruby cryptography encryption

使用 Bouncy CaSTLe PBEWITHSHA256AND128BITAES-CBC-BC 算法对 Java 中的字符串数据进行加密。很难用 ruby 解密它。我见过一些类似操作的示例,但没有看到 java PBEKeySpect 被加盐的示例(当然不确定这是否是问题所在)。对于某些上下文,这里是 Java 代码;

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC", 
            org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);

    KeySpec spec = new PBEKeySpec("password".toCharArray(), 
            "8 bytes!", 1024, 128);

    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();

    byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
    byte[] cipherText = cipher.doFinal("hello world".getBytes());

运行没有问题。然而,我们还没有发现在 Ruby 端解密它的神奇序列。如果有人愿意分享如何在 ruby​​ (1.9.3) 中解密的示例,我们将不胜感激。

更新

下面是 ruby​​ 中的解密代码,目前无法工作。

d = OpenSSL::Cipher.new("AES-128-CBC")
d.decrypt
key = OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "8 bytes!", 1024, d.key_len)
d.key = key
d.iv = iv.scan(/../).map{|b|b.hex}.pack('c*')
data = enc.scan(/../).map{|b|b.hex}.pack('c*')
d.update(data) << d.final

当 Java 端实现 PBKDF2WithHmacSHA1 算法时(显然),这个 ruby​​ 代码可以工作,但由于我无法详细说明的原因,我们不能再使用该实现(因此 PBEWITHSHA256AND128BITAES-CBC-BC)。

最佳答案

好的,就这样。您可能必须整理一些参数才能适应:

/**
 * Copied shamelessly from org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator,
 * changed only the hash algorithm.
 * All rights reserved by Bouncy Castle, see their MIT-like permissive license.
 * @author maartenb
 *
 */
public class PKCS5S2_SHA256_ParametersGenerator
    extends PBEParametersGenerator
{

    // NOTE this is the only actual change from PKCS5S2ParametersGenerator
    private Mac    hMac = new HMac(new SHA256Digest());

    /**
     * construct a PKCS5 Scheme 2 Parameters generator.
     */
    public PKCS5S2_SHA256_ParametersGenerator()
    {
    }

    private void F(
        byte[]  P,
        byte[]  S,
        int     c,
        byte[]  iBuf,
        byte[]  out,
        int     outOff)
    {
        byte[]              state = new byte[hMac.getMacSize()];
        CipherParameters    param = new KeyParameter(P);

        hMac.init(param);

        if (S != null)
        {
            hMac.update(S, 0, S.length);
        }

        hMac.update(iBuf, 0, iBuf.length);

        hMac.doFinal(state, 0);

        System.arraycopy(state, 0, out, outOff, state.length);

        if (c == 0)
        {
            throw new IllegalArgumentException("iteration count must be at least 1.");
        }

        for (int count = 1; count < c; count++)
        {
            hMac.init(param);
            hMac.update(state, 0, state.length);
            hMac.doFinal(state, 0);

            for (int j = 0; j != state.length; j++)
            {
                out[outOff + j] ^= state[j];
            }
        }
    }


    private void intToOctet(
        byte[]  buf,
        int     i)
    {
        buf[0] = (byte)(i >>> 24);
        buf[1] = (byte)(i >>> 16);
        buf[2] = (byte)(i >>> 8);
        buf[3] = (byte)i;
    }

    private byte[] generateDerivedKey(
        int dkLen)
    {
        int     hLen = hMac.getMacSize();
        int     l = (dkLen + hLen - 1) / hLen;
        byte[]  iBuf = new byte[4];
        byte[]  out = new byte[l * hLen];

        for (int i = 1; i <= l; i++)
        {
            intToOctet(iBuf, i);

            F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
        }

        return out;
    }

    /**
     * Generate a key parameter derived from the password, salt, and iteration
     * count we are currently initialised with.
     *
     * @param keySize the size of the key we want (in bits)
     * @return a KeyParameter object.
     */
    public CipherParameters generateDerivedParameters(
        int keySize)
    {
        keySize = keySize / 8;

        byte[]  dKey = generateDerivedKey(keySize);

        return new KeyParameter(dKey, 0, keySize);
    }

    /**
     * Generate a key with initialisation vector parameter derived from
     * the password, salt, and iteration count we are currently initialised
     * with.
     *
     * @param keySize the size of the key we want (in bits)
     * @param ivSize the size of the iv we want (in bits)
     * @return a ParametersWithIV object.
     */
    public CipherParameters generateDerivedParameters(
        int     keySize,
        int     ivSize)
    {
        keySize = keySize / 8;
        ivSize = ivSize / 8;

        byte[]  dKey = generateDerivedKey(keySize + ivSize);

        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
    }

    /**
     * Generate a key parameter for use with a MAC derived from the password,
     * salt, and iteration count we are currently initialised with.
     *
     * @param keySize the size of the key we want (in bits)
     * @return a KeyParameter object.
     */
    public CipherParameters generateDerivedMacParameters(
        int keySize)
    {
        return generateDerivedParameters(keySize);
    }
}

哦,当然,将 Bouncy 添加到您的路径中...这些是必需的导入语句:

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;

[编辑]示例用法

        int iterations = 1000; // minimum
        int keySize = 256; // maximum
        final byte[] salt = new byte[8];
        SecureRandom rng = SecureRandom.getInstance("SHA1PRNG");
        rng.nextBytes(salt);
        char[] password = new char[] { 'o', 'w', 'l', 's', 't', 'e', 'a', 'd' };

        // S2 *is* PBKDF2, but the default used only HMAC(SHA-1)
        final PKCS5S2_SHA256_ParametersGenerator gen = new PKCS5S2_SHA256_ParametersGenerator();

        // lets not use String, as we cannot destroy strings, BC to the rescue!
        final byte[] pwBytes = Strings.toUTF8ByteArray(password);

        gen.init(pwBytes, salt, iterations);

        final KeyParameter params1 = (KeyParameter) gen.generateDerivedMacParameters(keySize);

        // use for/next loop for older Java versions, destroy password information in memory
        Arrays.fill(pwBytes, 0, pwBytes.length, (byte) 0);
        Arrays.fill(password, 0, password.length, ' ');
        final KeyParameter keyParam = params1;
        SecretKeySpec secretKey = new SecretKeySpec(keyParam.getKey().clone(), "AES");

[编辑]忘记包含许可证,即使我指出它,对于合法化感到抱歉:

版权所有 (c) 2000 - 2011 The Legion Of The Bouncy CaSTLe (http://www.bouncycaSTLe.org)

特此免费授予获得本软件和相关文档文件(“软件”)副本的任何人,不受限制地使用本软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件的副本,并允许向其提供软件的人员这样做,但须满足以下条件:

上述版权声明和本许可声明应包含在本软件的所有副本或主要部分中。

本软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有者均不对因本软件或本软件中的使用或其他交易而产生或与之相关的任何 claim 、损害或其他责任负责,无论是契约(Contract)、侵权行为还是其他行为。软件。

关于java - AES PBE 在 Java 中加密/在 Ruby 中解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9526479/

相关文章:

java - Eclipse + m2e + junit5 - 已经可能了吗?

mysql - 主动记录查询以从三个关联模型中获取数据

security - 公共(public)重写函数 GetBytes() 因为 Byte() 已过时

python - 在 python 中生成使用 RSA key 签名的 JWT token

linux - Linux IPSEC 是否支持使用 AES GMAC 的 AH 传输?

java - 如何使用 Jface 同步两个 Eclipse 部件

java - "this"关键字不返回上下文

java - 为什么 Unicode 字符在数据库中正确显示,但显示为?当通过 Hibernate 在 Java 中打印时?

ruby - ruby 中的树和图数据结构

ruby-on-rails - Ruby 哈希值遍历和更改值不起作用