]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
chunk: Add function to calculate Internet Checksums according to RFC 1071
authorTobias Brunner <tobias@strongswan.org>
Tue, 15 Jul 2014 11:14:46 +0000 (13:14 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 22 Jul 2014 09:10:35 +0000 (11:10 +0200)
src/libstrongswan/tests/suites/test_chunk.c
src/libstrongswan/utils/chunk.c
src/libstrongswan/utils/chunk.h

index b33d70ec744a73c1ed4d21a6c50bd1f44da420a6..d71e010a2dd988a75fadc5cf3b03e1e4bb182ab2 100644 (file)
@@ -783,6 +783,51 @@ START_TEST(test_chunk_hash_static)
 }
 END_TEST
 
+/*******************************************************************************
+ * test for chunk_internet_checksum[_inc]()
+ */
+
+START_TEST(test_chunk_internet_checksum)
+{
+       chunk_t chunk;
+       u_int16_t sum;
+
+       chunk = chunk_from_chars(0x45,0x00,0x00,0x30,0x44,0x22,0x40,0x00,0x80,0x06,
+                                                        0x00,0x00,0x8c,0x7c,0x19,0xac,0xae,0x24,0x1e,0x2b);
+
+       sum = chunk_internet_checksum(chunk);
+       ck_assert_int_eq(0x442e, ntohs(sum));
+
+       sum = chunk_internet_checksum(chunk_create(chunk.ptr, 10));
+       sum = chunk_internet_checksum_inc(chunk_create(chunk.ptr+10, 10), sum);
+       ck_assert_int_eq(0x442e, ntohs(sum));
+
+       /* need to compensate for even/odd alignment */
+       sum = chunk_internet_checksum(chunk_create(chunk.ptr, 9));
+       sum = ntohs(sum);
+       sum = chunk_internet_checksum_inc(chunk_create(chunk.ptr+9, 11), sum);
+       sum = ntohs(sum);
+       ck_assert_int_eq(0x442e, ntohs(sum));
+
+       chunk = chunk_from_chars(0x45,0x00,0x00,0x30,0x44,0x22,0x40,0x00,0x80,0x06,
+                                                        0x00,0x00,0x8c,0x7c,0x19,0xac,0xae,0x24,0x1e);
+
+       sum = chunk_internet_checksum(chunk);
+       ck_assert_int_eq(0x4459, ntohs(sum));
+
+       sum = chunk_internet_checksum(chunk_create(chunk.ptr, 10));
+       sum = chunk_internet_checksum_inc(chunk_create(chunk.ptr+10, 9), sum);
+       ck_assert_int_eq(0x4459, ntohs(sum));
+
+       /* need to compensate for even/odd alignment */
+       sum = chunk_internet_checksum(chunk_create(chunk.ptr, 9));
+       sum = ntohs(sum);
+       sum = chunk_internet_checksum_inc(chunk_create(chunk.ptr+9, 10), sum);
+       sum = ntohs(sum);
+       ck_assert_int_eq(0x4459, ntohs(sum));
+}
+END_TEST
+
 /*******************************************************************************
  * test for chunk_map and friends
  */
@@ -1018,6 +1063,10 @@ Suite *chunk_suite_create()
        tcase_add_test(tc, test_chunk_hash_static);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("chunk_internet_checksum");
+       tcase_add_test(tc, test_chunk_internet_checksum);
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("chunk_map");
        tcase_add_test(tc, test_chunk_map);
        suite_add_tcase(s, tc);
index 1a9674f4dbc46d1b332164f978a53703752840c7..4b24b37c25b03f2c8d9be78021832444fb74c357 100644 (file)
@@ -987,6 +987,37 @@ u_int32_t chunk_hash_static(chunk_t chunk)
        return chunk_mac(chunk, static_key);
 }
 
+/**
+ * Described in header.
+ */
+u_int16_t chunk_internet_checksum_inc(chunk_t data, u_int16_t checksum)
+{
+       u_int32_t sum = ntohs(~checksum);
+
+       while (data.len > 1)
+       {
+               sum += untoh16(data.ptr);
+               data = chunk_skip(data, 2);
+       }
+       if (data.len)
+       {
+               sum += (u_int16_t)*data.ptr << 8;
+       }
+       while (sum >> 16)
+       {
+               sum = (sum & 0xffff) + (sum >> 16);
+       }
+       return htons(~sum);
+}
+
+/**
+ * Described in header.
+ */
+u_int16_t chunk_internet_checksum(chunk_t data)
+{
+       return chunk_internet_checksum_inc(data, 0xffff);
+}
+
 /**
  * Described in header.
  */
index 9951ff31f761077d4107dd0adab324d1980e2282..0daa2e1d0d6444da04e74e9b818528a528cc4e8c 100644 (file)
@@ -411,6 +411,31 @@ u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash);
  */
 u_int64_t chunk_mac(chunk_t chunk, u_char *key);
 
+/**
+ * Calculate the Internet Checksum according to RFC 1071 for the given chunk.
+ *
+ * If the result is used with chunk_internet_checksum_inc() and the data length
+ * is not a multiple of 16 bit the checksum bytes have to be swapped to
+ * compensate the even/odd alignment.
+ *
+ * @param chunk                        data to process
+ * @return                             checksum (one's complement, network order)
+ */
+u_int16_t chunk_internet_checksum(chunk_t data);
+
+/**
+ * Extend the given Internet Checksum (one's complement, in network byte order)
+ * with the given data.
+ *
+ * If data is not a multiple of 16 bits the checksum may have to be swapped to
+ * compensate even/odd alignment (see chunk_internet_checksum()).
+ *
+ * @param chunk                        data to process
+ * @param checksum             previous checksum (one's complement, network order)
+ * @return                             checksum (one's complement, network order)
+ */
+u_int16_t chunk_internet_checksum_inc(chunk_t data, u_int16_t checksum);
+
 /**
  * printf hook function for chunk_t.
  *