Added properly working CBC mode implementation to AES.
[crypto.git] / lib / silccrypt / ciphers_def.h
index c550827e4ea30ada95443633df11c4fb2e7ed5ed..cf6c6d51382e5d4a5967a4ca793a3086f37e3738 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1999 - 2007 Pekka Riikonen
+  Copyright (C) 1999 - 2008 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -20,6 +20,9 @@
 #ifndef CIPHERS_DEF_H
 #define CIPHERS_DEF_H
 
+
+#include "silclog.h"
+
 /* General definitions for algorithms */
 typedef unsigned char u1byte;
 typedef SilcUInt32 u4byte;
@@ -39,7 +42,93 @@ do {                                         \
     SILC_GET32_LSB(d[_i], s + (_i * 4));       \
 } while(0);
 
-/* CBC mode 128-bit block, LSB, 32-bit block argument must be encrypted */
+/* CBC mode 128-bit block, LSB, 8-bit iv argument must be encrypted */
+
+#ifndef WORDS_BIGENDIAN
+#ifdef SILC_X86_64
+/* x86-64 */
+#define SILC_CBC_ENC_MSB_128_8(len, iv, src, dst, i, enc)              \
+do {                                                                   \
+  SILC_ASSERT((len & (16 - 1)) == 0);                                  \
+  if (len & (16 - 1))                                                  \
+    return FALSE;                                                      \
+                                                                       \
+  for (i = 0; i < len; i += 16) {                                      \
+    *(SilcUInt64 *)iv ^= *(SilcUInt64 *)src;                           \
+    *(SilcUInt64 *)(iv + 8) ^= *(SilcUInt64 *)(src + 8);               \
+                                                                       \
+    enc;                                                               \
+                                                                       \
+    *(SilcUInt64 *)dst = *(SilcUInt64 *)iv;                            \
+    *(SilcUInt64 *)(dst + 8) = *(SilcUInt64 *)(iv + 8);                        \
+                                                                       \
+    dst += 16;                                                         \
+    src += 16;                                                         \
+  }                                                                    \
+} while(0)
+#else /* !SILC_X86_64 */
+/* x86 */
+#define SILC_CBC_ENC_MSB_128_8(len, iv, src, dst, i, enc)              \
+do {                                                                   \
+  SILC_ASSERT((len & (16 - 1)) == 0);                                  \
+  if (len & (16 - 1))                                                  \
+    return FALSE;                                                      \
+                                                                       \
+  for (i = 0; i < len; i += 16) {                                      \
+    *(SilcUInt32 *)iv ^= *(SilcUInt32 *)src;                           \
+    *(SilcUInt32 *)(iv + 4) ^= *(SilcUInt32 *)(src + 4);               \
+    *(SilcUInt32 *)(iv + 8) ^= *(SilcUInt32 *)(src + 8);               \
+    *(SilcUInt32 *)(iv + 12) ^= *(SilcUInt32 *)(src + 12);             \
+                                                                       \
+    enc;                                                               \
+                                                                       \
+    memcpy(dst, iv, 16);                                               \
+    dst += 16;                                                         \
+    src += 16;                                                         \
+  }                                                                    \
+} while(0)
+#endif /* SILC_X86_64 */
+#else /* WORDS_BIGENDIAN */
+/* big-endian machines */
+#define SILC_CBC_ENC_MSB_128_8(len, iv, src, dst, i, enc)              \
+do {                                                                   \
+  SilcUInt32 tmp[4], tmp2[4];                                          \
+                                                                       \
+  SILC_ASSERT((len & (16 - 1)) == 0);                                  \
+  if (len & (16 - 1))                                                  \
+    return FALSE;                                                      \
+                                                                       \
+  for (i = 0; i < len; i += 16) {                                      \
+    SILC_GET32_MSB(tmp[0], &iv[0]);                                    \
+    SILC_GET32_MSB(tmp[1], &iv[4]);                                    \
+    SILC_GET32_MSB(tmp[2], &iv[8]);                                    \
+    SILC_GET32_MSB(tmp[3], &iv[12]);                                   \
+                                                                       \
+    SILC_GET32_MSB(tmp2[0], &src[0]);                                  \
+    SILC_GET32_MSB(tmp2[1], &src[4]);                                  \
+    SILC_GET32_MSB(tmp2[2], &src[8]);                                  \
+    SILC_GET32_MSB(tmp2[3], &src[12]);                                 \
+                                                                       \
+    tmp[0] = tmp[0] ^ tmp2[0];                                         \
+    tmp[1] = tmp[1] ^ tmp2[1];                                         \
+    tmp[2] = tmp[2] ^ tmp2[2];                                         \
+    tmp[3] = tmp[3] ^ tmp2[3];                                         \
+                                                                       \
+    SILC_PUT32_MSB(tmp[0], &iv[0]);                                    \
+    SILC_PUT32_MSB(tmp[1], &iv[4]);                                    \
+    SILC_PUT32_MSB(tmp[2], &iv[8]);                                    \
+    SILC_PUT32_MSB(tmp[3], &iv[12]);                                   \
+                                                                       \
+    enc;                                                               \
+                                                                       \
+    memcpy(dst, iv, 16);                                               \
+    dst += 16;                                                         \
+    src += 16;                                                         \
+  }                                                                    \
+} while(0)
+#endif /* !WORDS_BIGENDIAN */
+
+/* CBC mode 128-bit block, MSB, 32-bit block argument must be encrypted */
 
 #define SILC_CBC_ENC_LSB_128_32(len, iv, block, src, dst, i, enc)      \
 do {                                                                   \
@@ -80,7 +169,7 @@ do {                                                                 \
 #define SILC_CBC_DEC_LSB_128_32(len, iv, block_prev, block,            \
                                block_dec, src, dst, i, dec)            \
 do {                                                                   \
-  if (len & (16 - 1))                                                  \
+  if (!len || len & (16 - 1))                                          \
     return FALSE;                                                      \
                                                                        \
   SILC_GET32_LSB(block_prev[0], &iv[0]);                               \
@@ -157,12 +246,106 @@ do {                                                                     \
   SILC_PUT32_MSB(block[3], &iv[12]);                                   \
 } while(0)
 
+/* CBC mode 128-bit block, LSB, 8-bit src argument must be decrypted
+   to dst. */
+
+#ifndef WORDS_BIGENDIAN
+#ifdef SILC_X86_64
+/* x86-64 */
+#define SILC_CBC_DEC_MSB_128_8(len, iv, prev, src, dst, i, dec)                \
+{                                                                      \
+  SILC_ASSERT((len & (16 - 1)) == 0);                                  \
+  if (len & (16 - 1))                                                  \
+    return FALSE;                                                      \
+                                                                       \
+  for (i = 0; i < len; i += 16) {                                      \
+    *(SilcUInt64 *)prev = *(SilcUInt64 *)src;                          \
+    *(SilcUInt64 *)(prev + 8) = *(SilcUInt64 *)(src + 8);              \
+                                                                       \
+    dec;                                                               \
+                                                                       \
+    *(SilcUInt64 *)dst ^= *(SilcUInt64 *)iv;                           \
+    *(SilcUInt64 *)(dst + 8) ^= *(SilcUInt64 *)(iv + 8);               \
+    *(SilcUInt64 *)iv = *(SilcUInt64 *)prev;                           \
+    *(SilcUInt64 *)(iv + 8) = *(SilcUInt64 *)(prev + 8);               \
+                                                                       \
+    dst += 16;                                                         \
+    src += 16;                                                         \
+  }                                                                    \
+} while(0)
+#else /* !SILC_X86_64 */
+/* x86 */
+#define SILC_CBC_DEC_MSB_128_8(len, iv, prev, src, dst, i, dec)                \
+do {                                                                   \
+  SILC_ASSERT((len & (16 - 1)) == 0);                                  \
+  if (len & (16 - 1))                                                  \
+    return FALSE;                                                      \
+                                                                       \
+  for (i = 0; i < len; i += 16) {                                      \
+    memcpy(prev, src, 16);                                             \
+                                                                       \
+    dec;                                                               \
+                                                                       \
+    *(SilcUInt32 *)dst ^= *(SilcUInt32 *)iv;                           \
+    *(SilcUInt32 *)(dst + 4) ^= *(SilcUInt32 *)(iv + 4);               \
+    *(SilcUInt32 *)(dst + 8) ^= *(SilcUInt32 *)(iv + 8);               \
+    *(SilcUInt32 *)(dst + 12) ^= *(SilcUInt32 *)(iv + 12);             \
+    memcpy(iv, prev, 16);                                              \
+                                                                       \
+    dst += 16;                                                         \
+    src += 16;                                                         \
+  }                                                                    \
+} while(0)
+#endif /* SILC_X86_64 */
+#else /* WORDS_BIGENDIAN */
+/* big-endian machines */
+#define SILC_CBC_DEC_MSB_128_8(len, iv, prev, src, dst, i, dec)                \
+do {                                                                   \
+  SilcUInt32 tmp2[4], tmp3[4];                                         \
+                                                                       \
+  SILC_ASSERT((len & (16 - 1)) == 0);                                  \
+  if (len & (16 - 1))                                                  \
+    return FALSE;                                                      \
+                                                                       \
+  for (i = 0; i < len; i += 16) {                                      \
+    memcpy(prev, src, 16);                                             \
+                                                                       \
+    dec;                                                               \
+                                                                       \
+    SILC_GET32_MSB(tmp2[0], &iv[0]);                                   \
+    SILC_GET32_MSB(tmp2[1], &iv[4]);                                   \
+    SILC_GET32_MSB(tmp2[2], &iv[8]);                                   \
+    SILC_GET32_MSB(tmp2[3], &iv[12]);                                  \
+                                                                       \
+    SILC_GET32_MSB(tmp3[0], &dst[0]);                                  \
+    SILC_GET32_MSB(tmp3[1], &dst[4]);                                  \
+    SILC_GET32_MSB(tmp3[2], &dst[8]);                                  \
+    SILC_GET32_MSB(tmp3[3], &dst[12]);                                 \
+                                                                       \
+    tmp2[0] = tmp3[0] ^ tmp2[0];                                       \
+    tmp2[1] = tmp3[1] ^ tmp2[1];                                       \
+    tmp2[2] = tmp3[2] ^ tmp2[2];                                       \
+    tmp2[3] = tmp3[3] ^ tmp2[3];                                       \
+                                                                       \
+    SILC_PUT32_MSB(tmp2[0], &dst[0]);                                  \
+    SILC_PUT32_MSB(tmp2[1], &dst[4]);                                  \
+    SILC_PUT32_MSB(tmp2[2], &dst[8]);                                  \
+    SILC_PUT32_MSB(tmp2[3], &dst[12]);                                 \
+                                                                       \
+    memcpy(iv, prev, 16);                                              \
+                                                                       \
+    dst += 16;                                                         \
+    src += 16;                                                         \
+  }                                                                    \
+} while(0)
+#endif /* !WORDS_BIGENDIAN */
+
 /* CBC mode 128-bit block, MSB, decrypt block to block_dec. */
 
 #define SILC_CBC_DEC_MSB_128_32(len, iv, block_prev, block,            \
                                block_dec, src, dst, i, dec)            \
 do {                                                                   \
-  if (len & (16 - 1))                                                  \
+  if (!len || len & (16 - 1))                                          \
     return FALSE;                                                      \
                                                                        \
   SILC_GET32_MSB(block_prev[0], &iv[0]);                               \
@@ -236,7 +419,7 @@ do {                                                                        \
 #define SILC_CBC_DEC_MSB_64_32(len, iv, block_prev, block,             \
                               block_dec, src, dst, i, dec)             \
 do {                                                                   \
-  if (len & (8 - 1))                                                   \
+  if (!len || len & (8 - 1))                                           \
     return FALSE;                                                      \
                                                                        \
   SILC_GET32_MSB(block_prev[0], &iv[0]);                               \
@@ -265,147 +448,103 @@ do {                                                                    \
   SILC_PUT32_MSB(block[1], &iv[4]);                                    \
 } while(0)
 
+#ifndef WORDS_BIGENDIAN
 
-/* CTR mode 128-bit block, MSB, MSB counter, the 8-bit enc_ctr argument must
-   be encrypted */
+/* CTR mode 128-bit block, MSB, MSB counter, the 8-bit ctr argument must
+   be encrypted to enc_ctr */
 
-#define SILC_CTR_MSB_128_8(iv, ctr, enc_ctr, pad, src, dst, enc)       \
+#define SILC_CTR_MSB_128_8(ctr, enc_ctr, pad, src, dst, enc)           \
 do {                                                                   \
-  SILC_GET32_MSB(ctr[0], iv);                                          \
-  SILC_GET32_MSB(ctr[1], iv + 4);                                      \
-  SILC_GET32_MSB(ctr[2], iv + 8);                                      \
-  SILC_GET32_MSB(ctr[3], iv + 12);                                     \
-                                                                       \
-  if (pad == 0)                                                                \
-    pad = 16;                                                          \
-                                                                       \
-  while (len-- > 0) {                                                  \
+  while (len > 0) {                                                    \
     if (pad == 16) {                                                   \
-      if (++ctr[3] == 0)                                               \
-       if (++ctr[2] == 0)                                              \
-         if (++ctr[1] == 0)                                            \
-           ++ctr[0];                                                   \
-                                                                       \
-      SILC_PUT32_MSB(ctr[0], enc_ctr);                                 \
-      SILC_PUT32_MSB(ctr[1], enc_ctr + 4);                             \
-      SILC_PUT32_MSB(ctr[2], enc_ctr + 8);                             \
-      SILC_PUT32_MSB(ctr[3], enc_ctr + 12);                            \
+      for (i = 15; i >= 0; i--)                                                \
+       if (++ctr[i])                                                   \
+         break;                                                        \
                                                                        \
       enc;                                                             \
+                                                                       \
+      if (len >= 16) {                                                 \
+       *(SilcUInt64 *)dst = *(SilcUInt64 *)src ^ *(SilcUInt64 *)enc_ctr; \
+       *(SilcUInt64 *)(dst + 8) = *(SilcUInt64 *)(src + 8) ^           \
+         *(SilcUInt64 *)(enc_ctr + 8);                                 \
+       src += 16;                                                      \
+       dst += 16;                                                      \
+       len -= 16;                                                      \
+       silc_prefetch((void *)src, 0, 0);                               \
+       continue;                                                       \
+      }                                                                        \
       pad = 0;                                                         \
     }                                                                  \
     *dst++ = *src++ ^ enc_ctr[pad++];                                  \
+    len--;                                                             \
   }                                                                    \
-                                                                       \
-  SILC_PUT32_MSB(ctr[0], iv);                                          \
-  SILC_PUT32_MSB(ctr[1], iv + 4);                                      \
-  SILC_PUT32_MSB(ctr[2], iv + 8);                                      \
-  SILC_PUT32_MSB(ctr[3], iv + 12);                                     \
 } while(0)
 
-/* CTR mode 128-bit block, MSB, MSB counter, the 32-bit ctr argument must
-   be encrypted to enc_ctr */
+#else /* WORDS_BIGENDIAN */
 
-#define SILC_CTR_MSB_128_32(iv, ctr, enc_ctr, pad, src, dst, enc)      \
+#define SILC_CTR_MSB_128_8(ctr, enc_ctr, pad, src, dst, enc)           \
 do {                                                                   \
-  SILC_GET32_MSB(ctr[0], iv);                                          \
-  SILC_GET32_MSB(ctr[1], iv + 4);                                      \
-  SILC_GET32_MSB(ctr[2], iv + 8);                                      \
-  SILC_GET32_MSB(ctr[3], iv + 12);                                     \
-                                                                       \
-  if (pad == 0)                                                                \
-    pad = 16;                                                          \
-                                                                       \
   while (len-- > 0) {                                                  \
     if (pad == 16) {                                                   \
-      if (++ctr[3] == 0)                                               \
-       if (++ctr[2] == 0)                                              \
-         if (++ctr[1] == 0)                                            \
-           ++ctr[0];                                                   \
+      for (i = 15; i >= 0; i--)                                                \
+       if (++ctr[i])                                                   \
+         break;                                                        \
                                                                        \
       enc;                                                             \
-      SILC_PUT32_MSB(enc_ctr[0], iv);                                  \
-      SILC_PUT32_MSB(enc_ctr[1], iv + 4);                              \
-      SILC_PUT32_MSB(enc_ctr[2], iv + 8);                              \
-      SILC_PUT32_MSB(enc_ctr[3], iv + 12);                             \
       pad = 0;                                                         \
     }                                                                  \
     *dst++ = *src++ ^ enc_ctr[pad++];                                  \
   }                                                                    \
-                                                                       \
-  SILC_PUT32_MSB(ctr[0], iv);                                          \
-  SILC_PUT32_MSB(ctr[1], iv + 4);                                      \
-  SILC_PUT32_MSB(ctr[2], iv + 8);                                      \
-  SILC_PUT32_MSB(ctr[3], iv + 12);                                     \
 } while(0)
 
-/* CTR mode 128-bit block, LSB, MSB counter, the 32-bit enc_ctr argument
-   must be encrypted */
+#endif /* !WORDS_BIGENDIAN */
+
+/* CTR mode 128-bit block, LSB, MSB counter, the 32-bit tmp argument
+   must be encrypted, enc_ctr must have the encrypted data too.  */
 
-#define SILC_CTR_LSB_128_32(iv, ctr, enc_ctr, pad, src, dst, enc)      \
+#define SILC_CTR_LSB_128_32(ctr, tmp, enc_ctr, pad, src, dst, enc)     \
 do {                                                                   \
-  SILC_GET32_MSB(ctr[0], iv);                                          \
-  SILC_GET32_MSB(ctr[1], iv + 4);                                      \
-  SILC_GET32_MSB(ctr[2], iv + 8);                                      \
-  SILC_GET32_MSB(ctr[3], iv + 12);                                     \
-                                                                       \
-  if (pad == 0)                                                                \
-    pad = 16;                                                          \
-                                                                       \
   while (len-- > 0) {                                                  \
     if (pad == 16) {                                                   \
-      if (++ctr[3] == 0)                                               \
-       if (++ctr[2] == 0)                                              \
-         if (++ctr[1] == 0)                                            \
-           ++ctr[0];                                                   \
-                                                                       \
-      enc_ctr[0] = SILC_SWAB_32(ctr[0]);                               \
-      enc_ctr[1] = SILC_SWAB_32(ctr[1]);                               \
-      enc_ctr[2] = SILC_SWAB_32(ctr[2]);                               \
-      enc_ctr[3] = SILC_SWAB_32(ctr[3]);                               \
+      for (i = 15; i >= 0; i--)                                                \
+       if (++ctr[i])                                                   \
+         break;                                                        \
                                                                        \
+      SILC_GET32_LSB(tmp[0], ctr);                                     \
+      SILC_GET32_LSB(tmp[1], ctr + 4);                                 \
+      SILC_GET32_LSB(tmp[2], ctr + 8);                                 \
+      SILC_GET32_LSB(tmp[3], ctr + 12);                                        \
       enc;                                                             \
-      SILC_PUT32_LSB(enc_ctr[0], iv);                                  \
-      SILC_PUT32_LSB(enc_ctr[1], iv + 4);                              \
-      SILC_PUT32_LSB(enc_ctr[2], iv + 8);                              \
-      SILC_PUT32_LSB(enc_ctr[3], iv + 12);                             \
+      SILC_PUT32_LSB(tmp[0], enc_ctr);                                 \
+      SILC_PUT32_LSB(tmp[1], enc_ctr + 4);                             \
+      SILC_PUT32_LSB(tmp[2], enc_ctr + 8);                             \
+      SILC_PUT32_LSB(tmp[3], enc_ctr + 12);                            \
       pad = 0;                                                         \
     }                                                                  \
-    *dst++ = *src++ ^ iv[pad++];                                       \
+    *dst++ = *src++ ^ enc_ctr[pad++];                                  \
   }                                                                    \
-                                                                       \
-  SILC_PUT32_MSB(ctr[0], iv);                                          \
-  SILC_PUT32_MSB(ctr[1], iv + 4);                                      \
-  SILC_PUT32_MSB(ctr[2], iv + 8);                                      \
-  SILC_PUT32_MSB(ctr[3], iv + 12);                                     \
 } while(0)
 
-/* CTR mode 64-bit block, MSB, MSB counter, the 32-bit ctr argument must
-   be encrypted to enc_ctr */
+/* CTR mode 128-bit block, LSB, MSB counter, the 32-bit tmp argument
+   must be encrypted, enc_ctr must have the encrypted data too.  */
 
-#define SILC_CTR_MSB_64_32(iv, ctr, enc_ctr, pad, src, dst, enc)       \
+#define SILC_CTR_MSB_64_32(ctr, tmp, enc_ctr, pad, src, dst, enc)      \
 do {                                                                   \
-  SILC_GET32_MSB(ctr[0], iv);                                          \
-  SILC_GET32_MSB(ctr[1], iv + 4);                                      \
-                                                                       \
-  if (pad == 0)                                                                \
-    pad = 8;                                                           \
-                                                                       \
   while (len-- > 0) {                                                  \
     if (pad == 8) {                                                    \
-      if (++ctr[1] == 0)                                               \
-       ++ctr[0];                                                       \
+      for (i = 7; i >= 0; i--)                                         \
+       if (++ctr[i])                                                   \
+         break;                                                        \
                                                                        \
+      SILC_GET32_MSB(tmp[0], ctr);                                     \
+      SILC_GET32_MSB(tmp[1], ctr + 4);                                 \
       enc;                                                             \
-      SILC_PUT32_MSB(enc_ctr[0], iv);                                  \
-      SILC_PUT32_MSB(enc_ctr[1], iv + 4);                              \
+      SILC_PUT32_MSB(tmp[0], enc_ctr);                                 \
+      SILC_PUT32_MSB(tmp[1], enc_ctr + 4);                             \
       pad = 0;                                                         \
     }                                                                  \
-    *dst++ = *src++ ^ iv[pad++];                                       \
+    *dst++ = *src++ ^ enc_ctr[pad++];                                  \
   }                                                                    \
-                                                                       \
-  SILC_PUT32_MSB(ctr[0], iv);                                          \
-  SILC_PUT32_MSB(ctr[1], iv + 4);                                      \
 } while(0)
 
 /* CFB 128-bit block, LSB, the 32-bit cfb argument must be encrypted. */
@@ -438,6 +577,7 @@ do {                                                                        \
 
 #define SILC_CFB_DEC_LSB_128_32(iv, cfb, pad, src, dst, dec)           \
 do {                                                                   \
+  unsigned char temp;                                                  \
   while (len-- > 0) {                                                  \
     if (pad == 16) {                                                   \
       SILC_GET32_LSB(cfb[0], iv);                                      \
@@ -453,9 +593,9 @@ do {                                                                        \
       SILC_PUT32_LSB(cfb[3], iv + 12);                                 \
       pad = 0;                                                         \
     }                                                                  \
-    iv[pad] = *src ^ iv[pad];                                          \
-    *dst = iv[pad];                                                    \
-    iv[pad++] = *src;                                                  \
+    temp = *src;                                                       \
+    *dst = temp ^ iv[pad];                                             \
+    iv[pad++] = temp;                                                  \
     dst++;                                                             \
     src++;                                                             \
   }                                                                    \
@@ -491,6 +631,7 @@ do {                                                                        \
 
 #define SILC_CFB_DEC_MSB_128_32(iv, cfb, pad, src, dst, dec)           \
 do {                                                                   \
+  unsigned char temp;                                                  \
   while (len-- > 0) {                                                  \
     if (pad == 16) {                                                   \
       SILC_GET32_MSB(cfb[0], iv);                                      \
@@ -506,9 +647,9 @@ do {                                                                        \
       SILC_PUT32_MSB(cfb[3], iv + 12);                                 \
       pad = 0;                                                         \
     }                                                                  \
-    iv[pad] = *src ^ iv[pad];                                          \
-    *dst = iv[pad];                                                    \
-    iv[pad++] = *src;                                                  \
+    temp = *src;                                                       \
+    *dst = temp ^ iv[pad];                                             \
+    iv[pad++] = temp;                                                  \
     dst++;                                                             \
     src++;                                                             \
   }                                                                    \
@@ -540,6 +681,7 @@ do {                                                                        \
 
 #define SILC_CFB_DEC_MSB_64_32(iv, cfb, pad, src, dst, dec)            \
 do {                                                                   \
+  unsigned char temp;                                                  \
   while (len-- > 0) {                                                  \
     if (pad == 8) {                                                    \
       SILC_GET32_MSB(cfb[0], iv);                                      \
@@ -551,9 +693,9 @@ do {                                                                        \
       SILC_PUT32_MSB(cfb[1], iv + 4);                                  \
       pad = 0;                                                         \
     }                                                                  \
-    iv[pad] = *src ^ iv[pad];                                          \
-    *dst = iv[pad];                                                    \
-    iv[pad++] = *src;                                                  \
+    temp = *src;                                                       \
+    *dst = temp ^ iv[pad];                                             \
+    iv[pad++] = temp;                                                  \
     dst++;                                                             \
     src++;                                                             \
   }                                                                    \
@@ -578,15 +720,16 @@ do {                                                                      \
 /* CFB 128-bit block, MSB, the 8-bit iv argument must be decrypted. */
 
 #define SILC_CFB_DEC_MSB_128_8(iv, pad, src, dst, dec)                 \
- do {                                                                  \
+do {                                                                   \
+  unsigned char temp;                                                  \
   while (len-- > 0) {                                                  \
     if (pad == 16) {                                                   \
       dec;                                                             \
       pad = 0;                                                         \
     }                                                                  \
-    iv[pad] = *src ^ iv[pad];                                          \
-    *dst = iv[pad];                                                    \
-    iv[pad++] = *src;                                                  \
+    temp = *src;                                                       \
+    *dst = temp ^ iv[pad];                                             \
+    iv[pad++] = temp;                                                  \
     dst++;                                                             \
     src++;                                                             \
   }                                                                    \