- /* Decrypt the message */
- silc_cipher_decrypt(cipher, data, data, data_len - iv_len - mac_len,
- (iv_len ? data + (data_len - iv_len - mac_len) : NULL));
+ /* Decrypt the entire buffer into allocated decryption buffer, since we
+ do not reliably know its encrypted length (it may include unencrypted
+ data at the end). */
+
+ /* Get pointer to the IV */
+ ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
+ silc_cipher_get_iv(cipher));
+
+ /* Allocate buffer for decryption. Since there might be unencrypted
+ data at the end, it might not be multiple by block size, make it so. */
+ block_len = silc_cipher_get_block_len(cipher);
+ dlen = data_len - iv_len - mac_len;
+ if (dlen & (block_len - 1))
+ dlen += SILC_MESSAGE_PAD(dlen);
+ if (dlen > data_len - iv_len - mac_len)
+ dlen -= block_len;
+ dec = silc_malloc(dlen);
+
+ /* Decrypt */
+ silc_cipher_decrypt(cipher, data, dec, dlen, ivp);
+
+ /* Now verify the true length of the payload and copy the decrypted
+ part over the original data. First get data length, and then padding
+ length from the decrypted data. Then, copy over the original data. */
+
+ totlen = 2;
+ SILC_GET16_MSB(len, dec + totlen);
+ totlen += 2 + len;
+ if (totlen + iv_len + mac_len + 2 > data_len) {
+ memset(dec, 0, dlen);
+ silc_free(dec);
+ return FALSE;
+ }
+ SILC_GET16_MSB(len, dec + totlen);
+ totlen += 2 + len;
+ if (totlen + iv_len + mac_len > data_len) {
+ memset(dec, 0, dlen);
+ silc_free(dec);
+ return FALSE;
+ }
+
+ memcpy(data, dec, totlen);
+ memset(dec, 0, dlen);
+ silc_free(dec);
+