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.
Теперь вопрос заключается в том, как декодировать конверт перед выполнением реального дешифрования.
Любые предложения, как я мог бы выполнить декодирование?