使用 Java 解码 cryptlib 编码文本(不使用 cryptlib)
你好。
首先:我是 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 native”格式)-我找不到任何描述关于它在网上...
目前我最好的尝试是这个:
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: 最后一个块解密不完整
我有点绝望,所以如果这里有人可以帮助我,我会非常高兴...
编辑: 以下是加密代码 (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 上下文的会话密钥以 CRYPT_FORMAT_CRYPTLIB 格式封装解密的数据。 现在的问题是如何在执行真正的解密之前对信封进行解码。
有什么建议我可以如何执行解码吗?
Hello.
First of all: I'm new to stackOverflow and to the subject I'm talking about...
I am trying to avoid the usage of the cryptlib library for TripleDES encryption in my Java application (now i am using AES - to ensure the downward compatibility I also want to be able to decode the strings which were created with the cryptlib library but without the useage of JNI).
But none of the things I tried by now worked for me.
Configuration:
Algorithm: TripleDES
Mode: CBC
Format: CRYPT_FORMAT_CRYPTLIB
The key has a size of 16 byte (which is inconvenient, but BouncyCastle would support it).
And the encrypted data has a size which is not a multiple of 8 (for exmaple 81 byte).
In my wrapper of the library (also in C) the context is created this way:
cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_3DES);
cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE, CRYPT_MODE_CBC );
cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY, key, keyLen);
The envelope is created this way:
cryptCreateEnvelope( envelope, CRYPT_FORMAT_CRYPTLIB );
I think the problem is the format (since it is a "cryptlib native" format) - I can not find any description about it in the net...
Currently my best try was this one:
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);
I also tried different paddings, but I always end in one of these two Exceptions:
- javax.crypto.IllegalBlockSizeException:
data not block size aligned - javax.crypto.IllegalBlockSizeException:
last block incomplete in decryption
I'm getting a little desperate, so I would be really happy if someone here could help me...
EDIT:
Here is the code for the encryption (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 );
}
EDIT 2:
In comparision it is the same implementation as descripted in this mailing list.
But i want to decode it in Java...
EDIT 3:
I think the problem is, that the encrypted data is enveloped in cryptlib (as seen in the code).
EDIT 4:
I know know that the problem is the enveloping. The cryptlib uses the session key of the created crypt context to envelope the decrypted data in the CRYPT_FORMAT_CRYPTLIB format.
The question now is how to decode the envelope before performing the real decryption.
Any suggestions how i could perform the decoding?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我终于明白了。
经过调试cryptlib的源码,发现密文是HEX编码的CMS封装内容。
我使用这个在线解码器来分析ASN.1序列(CMS使用ASN.1表示法):
http://www.aggressivesoftware.com/tools/asn1decoder.php
之后,我可以使用 BouncyCastle 作为提供者在 Java 中重现解码和解密:
I finally got it.
After debugging the source of cryptlib, I found out that the encrypted text is HEX encoded CMS enveloped content.
I used this online decoder to analyze the ASN.1 sequence (CMS uses ASN.1 notation):
http://www.aggressivesoftware.com/tools/asn1decoder.php
After that I could reproduce the decoding and decryption in Java using BouncyCastle as provider:
这些异常似乎是直接由您输入的密文长度引起的。根据定义,CBC 会输出整数个块,因此它应该为我们提供 8 的倍数...此时我要问的问题是, cryptlib 到底在做什么?您能向我们展示您用来创建加密字符串的 cryptlib 代码吗?
The exceptions appear to lead directly from the ciphertext length you're putting in. By definition CBC outputs a whole number of blocks so it should be giving us a multiple of 8... The question I'd be asking at this point is, what on earth is cryptlib doing? Can you show us the cryptlib code you're using to create the encrypted string?