我正在用javascript(带有appcelerator)编写一个移动应用程序,它与用Java编写的服务器应用程序进行通信。 通信已加密。
现在我想在客户端上通过CRC实现完整性检查(服务器端已经由另一方完成)。 在正确计算CRC的同时,某些东西似乎打破了加密过程。这是一种非常奇怪的行为,我似乎无法绕过它。
服务器使用bouncycastles进行解密。
客户端通过以下方式将javascript对象发送到服务器:
然后服务器抛出异常:
bsc.sdk.security.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
at bsc.sdk.security.bouncycastle.crypto.paddings.PKCS7Padding.padCount(PKCS7Padding.java:62)
at bsc.sdk.security.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(PaddedBufferedBlockCipher.java:273)
at bsc.sdk.api.crypt.aes.AESCipher.doFinal(AESCipher.java:60)
at bsc.sdk.api.crypt.aes.AESCipher.decrypt(AESCipher.java:36)
现在这里有趣的部分开始了:只有在标题CRC位于某个范围内时才会发生异常。 我通过手动将原始CRC周围的整数写入标题块来测试它。当整数介于1963000000和1963990000之间的某个范围时,它会失败。这些数字可能不完全准确,但由于时间限制,我没有进一步测试。
当我在块中写一些其他的Int,例如2534528925时,一切都很好。
那么,有没有人知道为什么某些CRC似乎打破了AES算法的填充?
以下是客户的相关代码片段(如果您需要更多,请询问):
send: function (command, ) {
var commandString = JSON.stringify(command, null);
var commandBuffer = Ti.createBuffer({value: commandString});
var packageBuffer = this.setHeader(commandBuffer, 2);
// encrypt and reassign the header
var encrypted = EncryptionService.encrypt(packageBuffer);
var words = encrypted.words;
var encryptedWordsCount = words.length;
var encryptedBuffer = Ti.createBuffer({length: encryptedWordsCount * 4});
for (i = 0; i < encryptedWordsCount; i++) {
Ti.Codec.encodeNumber({
source: words[i],
dest: encryptedBuffer,
position: i * 4,
type: Ti.Codec.TYPE_INT,
byteOrder: Ti.Codec.BIG_ENDIAN
});
}
packageBuffer = this.setHeader(encryptedBuffer, 1);
Ti.Stream.write(this.socket, packageBuffer, this.writeCallback);
}
setHeader: function (commandBuffer, type) {
var commandBufferLength = commandBuffer.length;
var paddedCommandBufferLength = this.options.headerLength + commandBuffer.length;
var type = (!type || type == 2) ? 0x00000002 : ((type == 1) ? 0x00000001 : 0x00000000);
var buffer = Ti.createBuffer({
length: this.options.headerLength
});
// write sync byte
Ti.Codec.encodeNumber({
source: 0x55,
dest: buffer,
position: 0,
type: Ti.Codec.TYPE_BYTE,
byteOrder: Ti.Codec.BIG_ENDIAN
});
// write the type
Ti.Codec.encodeNumber({
source: type,
dest: buffer,
position: 1,
type: Ti.Codec.TYPE_INT,
byteOrder: Ti.Codec.BIG_ENDIAN
});
// write the contentLength
Ti.Codec.encodeNumber({
source: commandBufferLength,
dest: buffer,
position: 5,
type: Ti.Codec.TYPE_INT,
byteOrder: Ti.Codec.BIG_ENDIAN
});
computeChecksumFromByteArray(headerBuffer, buffer, 9, this.crcTable);
buffer.append(commandBuffer);
return buffer;
}
computeChecksumFromByteArray: function(array, destinationBuffer, destinationOffset, crcTable){
var crc = -1;
for(var i=0, l=array.length; i<l; i++)
{
crc = crc >>> 8 ^ crcTable[ crc & 255 ^ array[i] ];
}
crc = (crc ^ -1) >>> 0;
Ti.Codec.encodeNumber({
source: crc,
dest: destinationBuffer,
position: destinationOffset,
type: Ti.Codec.TYPE_INT,
byteOrder: Ti.Codec.BIG_ENDIAN
});
}
EncryptionService.encrypt : function(buffer) {
var key = App.authentication.sharedSecret;
var bufferLength = buffer.length;
var bufferHexString = App.Library.Helper.createHexString(buffer);
var bufferWords = CryptoJS.enc.Hex.parse(bufferHexString);
var options = {
iv : CryptoJS.enc.Hex.parse('00000000000000000000000000000000'),
padding : CryptoJS.pad.Pkcs7,
mode : CryptoJS.mode.CBC
};
var encrypted = CryptoJS.AES.encrypt(bufferWords, key, options);
return encrypted.ciphertext;
}