Декодировать кодированный в cryptlib текст с помощью Java (без cryptlib) - PullRequest
0 голосов
/ 16 мая 2011

Hello.

Прежде всего: я новичок в stackOverflow и в теме, о которой я говорю ...
Я пытаюсь избежать использования библиотеки cryptlib для шифрования TripleDES в моем приложении Java (сейчас я использую AES - для обеспечения обратной совместимости, я также хочу иметь возможность декодировать строки, созданные с помощью библиотека cryptlib, но без использования JNI).
Но ничто из того, что я пробовал, не помогло мне.

Конфигурация:
Алгоритм: TripleDES
Режим: CBC
Формат: CRYPT_FORMAT_CRYPTLIB
Ключ имеет размер 16 байт (что неудобно, но BouncyCastle будет его поддерживать).
И зашифрованные данные имеют размер , а не , кратный 8 (например, 81 байт).

В моей оболочке библиотеки (также в C) контекст создается следующим образом:

cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_3DES);
cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE, CRYPT_MODE_CBC );
cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY, key, keyLen); 

Конверт создается следующим образом:

cryptCreateEnvelope( envelope, CRYPT_FORMAT_CRYPTLIB );

Я думаю, что проблема в формате (так как это "родной" формат cryptlib) - я не могу найти никакого описания об этом в сети ...

На данный момент моя лучшая попытка была такая:

Security.addProvider(new BouncyCastleProvider());
SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher e_cipher = Cipher.getInstance("DESede/CBC/PKCS7Padding", "BC");
e_cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

byte[] hexdecoded = Hex.decode(ENCRYPTED.getBytes());
byte [] cipherText = e_cipher.doFinal(hexdecoded);

return new String(cipherText);

Я также пробовал разные отступы, но всегда заканчиваю одним из этих двух исключений:

  • javax.crypto.IllegalBlockSizeException: данные не выровнены по размеру блока
  • javax.crypto.IllegalBlockSizeException: последний блок не полностью расшифрован

Я немного отчаялся, поэтому я был бы очень рад, если бы кто-то здесь мог мне помочь ...

EDIT: Вот код для шифрования (CryptData.cpp):

bool CCryptData::encryptData(BYTE *key,int keyLen, BYTE *data, int dataLen, int resultMemSize, BYTE *result, int &resultLen)
{
    CRYPT_ENVELOPE cryptEnvelope;
    CRYPT_CONTEXT cryptContext;
    CRYPT_ALGO cryptAlgo = selectCipher( CRYPT_ALGO_3DES );
    int count;

    /* Create the session key context.  We don't check for errors here since
       this code will already have been tested earlier */
    cryptCreateContext( &cryptContext, CRYPT_UNUSED, cryptAlgo );
    cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE, CRYPT_MODE_CBC );
    cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY, key, keyLen );

    /* Create the envelope, push in a password and the data, pop the
       enveloped result, and destroy the envelope */
    if( !createEnvelope( &cryptEnvelope ) || \
        !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SESSIONKEY,
                            cryptContext ) )
        return( FALSE );

    cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, dataLen );

    count = pushData( cryptEnvelope, data, dataLen, NULL, 0 );

    if( cryptStatusError( count ) )
        return( FALSE );

    resultLen = popData( cryptEnvelope, result, resultMemSize);

    if( cryptStatusError( count ) )
        return( FALSE );
    if( !destroyEnvelope( cryptEnvelope ) )
        return( FALSE );

    return true;
}

bool CCryptData::checkErrorStatus(int status, CString function)
{
    if( cryptStatusError( status ) )
    {
        m_lastError  = "Error occured in function " + function;
        m_lastError += " with StatusCode: " + status;
        m_bError = true;
        return true;
    }

    return false;
}

int CCryptData::createEnvelope( CRYPT_ENVELOPE *envelope )
{
    int status;

    /* Create the envelope */
    status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB );
    if( checkErrorStatus(status, "createEnvelope"))
        return false;

    return( TRUE );
}

int CCryptData::destroyEnvelope( CRYPT_ENVELOPE envelope )
{
    int status;

    /* Destroy the envelope */
    status = cryptDestroyEnvelope( envelope );
    if( checkErrorStatus( status, "destroyEnvelope"))
        return false;

    return( TRUE );

}

int CCryptData::pushData( const CRYPT_ENVELOPE envelope, const BYTE *buffer,
                         const int length, const void *stringEnvInfo,
                         const int numericEnvInfo )
{
    int status, bytesIn;

    /* Push in the data */
    status = cryptPushData( envelope, buffer, length, &bytesIn );
    if( cryptStatusError( status ) )
    {
        printf( "cryptPushData() failed with error code %d, line %d.\n",
                status, __LINE__ );
        return( status );
    }
    if( bytesIn != length )
    {
        printf( "cryptPushData() only copied %d of %d bytes, line %d.\n",
                bytesIn, length, __LINE__ );
        return( SENTINEL );
    }

    /* Flush the data */
    status = cryptPushData( envelope, NULL, 0, NULL );
    if( cryptStatusError( status ) && status != CRYPT_ERROR_COMPLETE )
        {
        printf( "cryptPushData() (flush) failed with error code %d, line "
                "%d.\n", status, __LINE__ );
        return( status );
        }

    return( bytesIn );

}

int CCryptData::popData( CRYPT_ENVELOPE envelope, BYTE *buffer, int bufferSize )
{
    int status, bytesOut;

    status = cryptPopData( envelope, buffer, bufferSize, &bytesOut );
    if( cryptStatusError( status ) )
        {
        printf( "cryptPopData() failed with error code %d, line %d.\n",
                status, __LINE__ );
        return( status );
        }

    return( bytesOut );

}

int CCryptData::addEnvInfoNumeric( const CRYPT_ENVELOPE envelope,
                              const CRYPT_ATTRIBUTE_TYPE type,
                              const int envInfo )
{
    int status;

    status = cryptSetAttribute( envelope, type, envInfo );
    if( checkErrorStatus( status, "addEnvInfoNumeric"))
        return false;

    return( TRUE );

}

CRYPT_ALGO CCryptData::selectCipher( const CRYPT_ALGO algorithm )
{
    if( cryptStatusOK( cryptQueryCapability( algorithm, NULL ) ) )
        return( algorithm );
    return( CRYPT_ALGO_BLOWFISH );
}

РЕДАКТИРОВАТЬ 2: Для сравнения, это та же реализация, что и описанная в этом списке рассылки .
Но я хочу расшифровать его на Java ...

РЕДАКТИРОВАТЬ 3: Я думаю, проблема в том, что зашифрованные данные заключены в cryptlib (как видно из кода).

РЕДАКТИРОВАТЬ 4: Я знаю, знаю, что проблема заключается в обволакивании. Cryptlib использует ключ сеанса созданного контекста крипты для конвертации дешифрованных данных в формат CRYPT_FORMAT_CRYPTLIB. Теперь вопрос заключается в том, как декодировать конверт перед выполнением реального дешифрования.
Любые предложения, как я мог бы выполнить декодирование?

Ответы [ 2 ]

1 голос
/ 30 мая 2011

Я наконец получил это.
После отладки источника cryptlib я обнаружил, что зашифрованный текст представляет собой HEX-закодированное содержимое CMS.
Я использовал этот онлайн-декодер для анализа последовательности ASN.1 (CMS использует нотацию ASN.1):
http://www.aggressivesoftware.com/tools/asn1decoder.php

После этого я мог воспроизвести декодирование и дешифрование в Java, используя BouncyCastle в качестве поставщика:


    public byte[] decrypt(final byte[] data) throws CryptoException {
        try {
            Security.addProvider(new BouncyCastleProvider());</p>

<pre><code>        EncryptedContentInfo encryptionInfo = parseContentInfo(data);
        AlgorithmIdentifier algoID = encryptionInfo.getContentEncryptionAlgorithm();

        // get the real encrypted data
        byte[] encryptedData = encryptionInfo.getEncryptedContent().getOctets();

        // extract the initialization vector from the algorithm identifier object
        byte[] ivBytes = ((ASN1OctetString) algoID.getParameters()).getOctets();
        // create the key depending on the algorithm
        SecretKeySpec keySpec = new SecretKeySpec(rawKey, algoID.getObjectId().getId());
        // request cipher
        Cipher c = Cipher.getInstance(algoID.getObjectId().getId(), CRYPT_PROVIDER);

        c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));
        byte[] decrypted = c.doFinal(encryptedData);

        return decrypted;

        } catch (NoSuchAlgorithmException e) {
            throw new CryptoException(e);
        } catch (NoSuchProviderException e) {
            throw new CryptoException(e);
        } catch (NoSuchPaddingException e) {
            throw new CryptoException(e);
        } catch (InvalidKeyException e) {
            throw new CryptoException(e);
        } catch (InvalidAlgorithmParameterException e) {
            throw new CryptoException(e);
        } catch (IllegalBlockSizeException e) {
            throw new CryptoException(e);
        } catch (BadPaddingException e) {
            throw new CryptoException(e);
        }
    }
}

private EncryptedContentInfo parseContentInfo(final byte[] encrypted) throws CryptoException { try { // create a new byte array stream ByteArrayInputStream bin = new ByteArrayInputStream(encrypted); // create an ASN.1 input stream ASN1InputStream ain = new ASN1InputStream(bin); // read the whole sequence ASN1Sequence mainSequence = (ASN1Sequence) ain.readObject(); // check if it is an encrypted data DERObjectIdentifier mainIdentifier = (DERObjectIdentifier) mainSequence .getObjectAt(ASN1IDENTIFIER_ID); if (!mainIdentifier.equals(OID_ENCRYPTED_DATA)) { throw new CryptoException("Given data is not encrypted CMS."); } // parse the encrypted object DERTaggedObject encryptedObject = (DERTaggedObject) mainSequence.getObjectAt(ASN1CONTENT_ID); // parse the sequence containing the useful informations ASN1Sequence encryptedSequence = (ASN1Sequence) encryptedObject.getObject(); // create the content info object EncryptedContentInfo info = EncryptedContentInfo.getInstance(encryptedSequence .getObjectAt(ASN1CONTENT_ID)); return info; } catch (IOException e) { // if the main sequence can not be read from the stream an IOException would be thrown throw new CryptoException(e); } catch (ClassCastException e) { // if the parsing fails, a ClassCastException would be thrown throw new CryptoException(e); } catch (IllegalStateException e) { // if the parsing fails, also a IllegalStateException can be thrown throw new CryptoException(e); } }

Таким образом, я смог декодировать данный текст, идентифицировать реальный алгоритм дешифрования и извлечь используемый вектор инициализации и реальные дешифрованные данные для выполнения дешифрования.

0 голосов
/ 17 мая 2011

Исключения, по-видимому, ведут непосредственно из длины зашифрованного текста, который вы вводите. По определению, CBC выводит целое число блоков, поэтому он должен давать нам кратное 8 ... Вопрос, который я хотел бы задать на этомДело в том, что на земле делает Cryptlib?Можете ли вы показать нам код cryptlib, который вы используете для создания зашифрованной строки?

...