将CRC添加到数据包会以某种方式破坏CryptoJS的AES

时间:2015-07-01 11:14:01

标签: javascript encryption appcelerator bouncycastle cryptojs

我正在用javascript(带有appcelerator)编写一个移动应用程序,它与用Java编写的服务器应用程序进行通信。 通信已加密。

现在我想在客户端上通过CRC实现完整性检查(服务器端已经由另一方完成)。 在正确计算CRC的同时,某些东西似乎打破了加密过程。这是一种非常奇怪的行为,我似乎无法绕过它。

服务器使用bouncycastles进行解密。

客户端通过以下方式将javascript对象发送到服务器:

  • 对象转换为json字符串
  • 然后将其转换为byteArray(确切地说是Titanium.Buffer) - 我将其称之为:content
  • 添加标题包含以下信息:
    • 5个字节指定数据包类型
    • 内容长度的4个字节
    • 4个字节用于标题的CRC32
    • 4个字节用于内容的CRC32
  • 内容会附加到标题中 - 我会称之为:packet
  • 数据包通过CBC模式下的cryptoJS AES进行加密
  • 加密数据包获取标题(通过与之前相同的方法)
  • 这会被发送到服务器

然后服务器抛出异常:

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;

}

0 个答案:

没有答案