cryptoapi java_CryptoAPI C ++使用AES加密算法与Java互操作

我必须做几件事来正确地得到消息:将KP_MODE明确设置为CRYPT_MODE_CBC ,将KP_MODE设置为0

在Java解密中使用NoPadding

不要反转密钥或消息的字节

在诊断问题方面,最有用的建议是在Java中设置NoPadding以防止BadPaddingException 。 这让我看到了结果 - 即使是错误的。

奇怪的是,RSA Java / CryptoAPI互操作解决方案要求消息完全按字节反转才能使用Java,但AES不希望密钥或消息是字节反转的。

CryptSetKeyParam不会让我使用ZERO_PADDING,但是当查看解密的字节时,很明显CryptoAPI会填充未使用的字节数。 例如,如果块大小为16,如果最后一个块仅使用9个字节,则剩余的5个字节将获得0x05的值。 这是否存在潜在的安全漏洞? 我应该用随机字节填充所有其他字节,并仅使用最后一个字节来表示使用了多少填充?

下面是工作代码(使用最后一个字节的填充计数的CryptoAPI约定)(为了简单起见,已经删除了来自Crypt的返回值的检查):// init and gen key

HCRYPTPROV provider;

CryptAcquireContext(&provider, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);

// Use symmetric key encryption

HCRYPTKEY sessionKey;

DWORD exportKeyLen;

BYTE iv[32];

memset(iv, 0, sizeof(iv));

DWORD padding = PKCS5_PADDING;

DWORD mode = CRYPT_MODE_CBC;

CryptGenKey(provider, CALG_AES_128, CRYPT_EXPORTABLE, &sessionKey);

CryptSetKeyParam(sessionKey, KP_IV, iv, 0);

CryptSetKeyParam(sessionKey, KP_PADDING, (BYTE*)&padding, 0);

CryptSetKeyParam(sessionKey, KP_MODE, (BYTE*)&mode, 0);

// Export key

BYTE exportKey[1024];

CryptExportKey(sessionKey, NULL, PLAINTEXTKEYBLOB, 0, exportKey, &exportKeyLen);

// skip PLAINTEXTKEYBLOB header

//      { uint8_t bType, uint8_t version, uint16_t reserved, uint32_t aiKey, uint32_t keySize }

DWORD keySize =  *((DWORD*)(exportKey + 8));

BYTE * rawKey = exportKey + 12;

// Encrypt message

BYTE encryptedMessage[1024];

const char * message = "Decryption Works -- using multiple blocks";

BYTE messageLen = (BYTE)strlen(message);

memcpy(encryptedMessage, message, messageLen);

DWORD encryptedMessageLen = messageLen;

CryptEncrypt(sessionKey, NULL, TRUE, 0, encryptedMessage, &encryptedMessageLen, sizeof(encryptedMessage));

BYTE byteEncryptedMessageLen = (BYTE)encryptedMessageLen;

FILE * f = fopen("test.aes", "wb");

fwrite(rawKey, 1, keySize, f);

fwrite(&byteEncryptedMessageLen, 1, sizeof(byteEncryptedMessageLen), f);

fwrite(encryptedMessage, 1, encryptedMessageLen, f);

fclose(f);

// destroy session key

CryptDestroyKey(sessionKey);

CryptReleaseContext(provider, 0);

Java解密:try

{

FileInputStream in = new FileInputStream("test.aes");

DataInputStream dataIn = new DataInputStream(in);

// stream key and message

byte[] rawKey = new byte[16];

dataIn.read(rawKey);

byte encryptedMessageLen = dataIn.readByte();

byte[] encryptedMessage = new byte[encryptedMessageLen];

dataIn.read(encryptedMessage);

// use CBC/NoPadding, with 0 IV -- (each message is creating it's own session key, so zero IV is ok)

SecretKeySpec sessionKey = new SecretKeySpec(rawKey, "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

cipher.init(Cipher.DECRYPT_MODE, sessionKey, new IvParameterSpec(new byte[16]));

byte[] decryptedBlocks = cipher.doFinal(encryptedMessage);

// check versus expected message

byte[] expectedBytes = "Decryption Works -- using multiple blocks".getBytes();

Assert.assertTrue("Incorrect Message" + new String(message), Arrays.equals(message, expectedBytes));

}

catch (Exception e) {

e.printStackTrace();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值