AES PBE шифрование в Java / расшифровка в Ruby - PullRequest
1 голос
/ 02 марта 2012

Использование алгоритма Bouncy Castle PBEWITHSHA256AND128BITAES-CBC-BC для шифрования строковых данных в Java. Трудно получить расшифровку в рубине. Я видел несколько примеров подобных операций, но ни один, где 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), он будет очень признателен.

UPDATE

Ниже приведен код дешифрования в 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

Этот код ruby ​​работал, когда сторона Java реализует алгоритм PBKDF2WithHmacSHA1 (очевидно), но по причинам, которые я не могу точно уточнить, мы больше не можем использовать эту реализацию (следовательно, PBEWITHSHA256AND128BITAES-CBC-BC).

1 Ответ

0 голосов
/ 03 марта 2012

ОК, идет. Возможно, вам придется маршалировать некоторые параметры, чтобы соответствовать:

/**
 * 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");

[EDIT] забыл включить лицензию, даже если я указал на нее, извините за легализацию:

Copyright (c) 2000 - 2011 Легион Надувного Замка (http://www.bouncycastle.org)

Настоящим предоставляется бесплатное разрешение любому лицу, получающему копию этого программного обеспечения и связанных с ним файлов документации (далее - «Программное обеспечение»), осуществлять операции с Программным обеспечением без ограничений, включая без ограничения права на использование, копирование, изменять, объединять, публиковать, распространять, сублицензировать и / или продавать копии Программного обеспечения и разрешать лицам, которым предоставляется Программное обеспечение, делать это при соблюдении следующих условий:

Вышеуказанное уведомление об авторских правах и это уведомление о разрешении должны быть включены во все копии или существенные части Программного обеспечения.

ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЯ ГАРАНТИЙ ТОВАРНОГО ОБЕСПЕЧЕНИЯ, ПРИГОДНОСТИ ДЛЯ ОСОБЫХ ЦЕЛЕЙ И НЕЗАКРЕПЛЕНИЙ. Ни при каких обстоятельствах авторы или держатели авторских прав не несут ответственности за любые претензии, ущерб или другую ответственность, возникающие в результате действия контракта, деликтного или иного действия, возникающие в результате, в результате или в связи с программным обеспечением или использованием в других отношениях. ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...