source: tools/traceanon/Anon.cc @ aafdc55

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since aafdc55 was ebb54a5, checked in by Shane Alcock <salcock@…>, 6 years ago

Improved parallel traceanon

  • Updated to use new parallel API.
  • Use libcrypto for AES operations.
  • Rename -f option to -F to avoid confusion with normal filtering options.
  • Add OO code for implementing anonymisation methods.
  • Add ability to anonymise IPv6 addresses using cryptopan.
  • Make sure ICMPv6 checksums are replaced.
  • Remove unnecessary testing code, e.g. hash functions, debug output.
  • Add maximum threads CLI option.
  • Replaced useless trace_help option with conventional -h option.
  • Property mode set to 100644
File size: 7.5 KB
Line 
1#include "config.h"
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5#include <assert.h>
6#include <arpa/inet.h>
7#include "Anon.h"
8
9
10static uint32_t masks[33] = {
11                0x00000000, 0x80000000, 0xC0000000, 0xe0000000, 0xf0000000,
12                0xf8000000, 0xfC000000, 0xfe000000, 0xff000000, 0xff800000,
13                0xffC00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffC0000,
14                0xfffe0000, 0xffff0000, 0xffff8000, 0xffffC000, 0xffffe000,
15                0xfffff000, 0xfffff800, 0xfffffC00, 0xfffffe00, 0xffffff00,
16                0xffffff80, 0xffffffC0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
17                0xfffffffC, 0xfffffffe, 0xffffffff,
18};
19
20
21Anonymiser::Anonymiser () {
22    /* empty constructor */
23}
24
25PrefixSub::PrefixSub(const char *ipv4_key, const char *ipv6_key) : Anonymiser() {
26    this->ipv4_mask = 0;
27    this->ipv4_prefix = 0;
28
29    memset(this->ipv6_mask, 0, 16);
30    memset(this->ipv6_prefix, 0, 16);
31
32    if (ipv4_key != NULL) {
33        int a,b,c,d;
34        int bits;
35
36        if (sscanf(ipv4_key, "%i.%i.%i.%i/%i", &a, &b, &c, &d, &bits) != 5) {
37            fprintf(stderr, "Invalid IPv4 prefix: %s\n", ipv4_key);
38
39        } else {
40            this->ipv4_prefix = (a<<24) + (b<<16) + (c<<8) + d;
41            if (bits < 0 || bits > 32) {
42                fprintf(stderr, "Invalid IPv4 prefix: %s\n", ipv4_key);
43            } else {
44                this->ipv4_mask = masks[bits];
45            }
46        }
47    }
48
49    /* TODO IPv6 */
50
51
52}
53
54PrefixSub::~PrefixSub() {
55
56}
57
58uint32_t PrefixSub::anonIPv4(uint32_t orig) {
59
60    return (this->ipv4_prefix & this->ipv4_mask) | (orig & ~this->ipv4_mask);
61
62}
63
64void PrefixSub::anonIPv6(uint8_t *orig, uint8_t *result) {
65
66    /* TODO */
67    memcpy(result, orig, 16);
68
69}
70
71#ifdef HAVE_LIBCRYPTO
72#include <openssl/evp.h>
73
74CryptoAnon::CryptoAnon(uint8_t *key, uint8_t len, uint8_t cachebits) :
75        Anonymiser() {
76
77    assert(len >= 32);
78    memcpy(this->key, key, 16);
79    memcpy(this->padding, key + 16, 16);
80
81    this->cipher = EVP_aes_128_ecb();
82    EVP_CIPHER_CTX_init(&this->ctx);
83
84    EVP_EncryptInit_ex(&this->ctx, this->cipher, NULL, this->key, NULL);
85
86    this->cachebits = cachebits;
87
88    this->ipv4_cache = new IPv4AnonCache();
89    this->ipv6_cache = new IPv6AnonCache();
90    this->recent_ipv4_cache[0][0] = 0;
91    this->recent_ipv4_cache[0][1] = 0;
92    this->recent_ipv4_cache[1][0] = 0;
93    this->recent_ipv4_cache[0][1] = 0;
94
95}
96
97
98CryptoAnon::~CryptoAnon() {
99    delete(this->ipv4_cache);
100    EVP_CIPHER_CTX_cleanup(&this->ctx);
101}
102
103static inline uint32_t generateFirstPad(uint8_t *pad) {
104    uint32_t fp = 0;
105
106    fp = (((uint32_t)pad[0]) << 24) + (((uint32_t)pad[1]) << 16) +
107            (((uint32_t)pad[2]) << 8) + (uint32_t)pad[3];
108    return fp;
109
110}
111
112uint32_t CryptoAnon::anonIPv4(uint32_t orig) {
113    uint32_t cacheprefix =
114            (orig >> (32 - this->cachebits)) << (32 - this->cachebits);
115    uint32_t result = 0;
116
117    if (this->recent_ipv4_cache[0][0] == orig)
118        return this->recent_ipv4_cache[0][1];
119    else if (this->recent_ipv4_cache[1][0] == orig) {
120        uint32_t tmp = this->recent_ipv4_cache[1][1];
121        this->recent_ipv4_cache[1][0] = this->recent_ipv4_cache[0][0];
122        this->recent_ipv4_cache[1][1] = this->recent_ipv4_cache[0][1];
123        this->recent_ipv4_cache[0][0] = orig;
124        this->recent_ipv4_cache[0][1] = tmp;
125        return tmp;
126
127    }
128
129    result = this->lookupv4Cache(cacheprefix);
130    result = this->encrypt32Bits(orig, this->cachebits, 32, result);
131
132    this->recent_ipv4_cache[1][0] = this->recent_ipv4_cache[0][0];
133    this->recent_ipv4_cache[1][1] = this->recent_ipv4_cache[0][1];
134    this->recent_ipv4_cache[0][0] = orig;
135    this->recent_ipv4_cache[0][1] = result ^ orig;
136
137    return this->recent_ipv4_cache[0][1];
138}
139
140static uint64_t swap64(uint64_t num) {
141    uint32_t swapa, swapb;
142    uint64_t res;
143
144    swapa = (num & 0xffffffff);
145    swapb = (num >> 32);
146    swapa = ntohl(swapa);
147    swapb = ntohl(swapb);
148    res =(uint64_t)swapa << 32 | (swapb);
149    return res;
150}
151
152void CryptoAnon::anonIPv6(uint8_t *orig, uint8_t *result) {
153
154    uint64_t prefix, anonprefixmap;
155    uint64_t suffix, anonsuffixmap;
156
157    memcpy(&prefix, orig, 8);
158    memcpy(&suffix, orig + 8, 8);
159
160    prefix = swap64(prefix);
161    suffix = swap64(suffix);
162
163    anonprefixmap = this->lookupv6Cache(prefix);
164    anonsuffixmap = this->lookupv6Cache(suffix);
165
166    prefix = (swap64(anonprefixmap ^ prefix));
167    suffix = (swap64(anonsuffixmap ^ suffix));
168
169    memcpy(result, &prefix, sizeof(uint64_t));
170    memcpy(result + sizeof(uint64_t), &suffix, sizeof(uint64_t));
171
172}
173
174uint32_t CryptoAnon::lookupv4Cache(uint32_t prefix) {
175
176    IPv4AnonCache::iterator it = this->ipv4_cache->find(prefix);
177
178    if (it == this->ipv4_cache->end()) {
179        uint32_t prefmask = this->encrypt32Bits(prefix, 0, this->cachebits, 0);
180        (*this->ipv4_cache)[prefix] = prefmask;
181        return prefmask;
182    }
183    return it->second;
184
185}
186
187uint64_t CryptoAnon::lookupv6Cache(uint64_t prefix) {
188    IPv6AnonCache::iterator it = this->ipv6_cache->find(prefix);
189
190    if (it == this->ipv6_cache->end()) {
191        uint64_t prefmask = this->encrypt64Bits(prefix);
192        (*this->ipv6_cache)[prefix] = prefmask;
193        return prefmask;
194    }
195    return it->second;
196}
197
198uint32_t CryptoAnon::encrypt32Bits(uint32_t orig, uint8_t start, uint8_t stop, 
199        uint32_t res) {
200    uint8_t rin_output[32];
201    uint8_t rin_input[16];
202    uint32_t first4pad;
203    int outl = 32;
204
205    memcpy(rin_input, this->padding, 16);
206    first4pad = generateFirstPad(this->padding);
207
208    for (int pos = start; pos < stop; pos ++) {
209        uint32_t input;
210
211        /* The MS bits are taken from the original address. The remaining
212         * bits are taken from padding. first4pad is used to help ensure we
213         * use the right bits from padding when pos < 32.
214         */
215        if (pos == 0) {
216            input = first4pad;
217        } else {
218            input = ((orig >> (32 - pos)) << (32 - pos)) |
219                    ((first4pad << pos) >> pos);
220        }
221
222        rin_input[0] = (uint8_t) (input >> 24);
223        rin_input[1] = (uint8_t) ((input << 8) >> 24);
224        rin_input[2] = (uint8_t) ((input << 16) >> 24);
225        rin_input[3] = (uint8_t) ((input << 24) >> 24);
226
227        /* Encryption: we're using AES as a pseudorandom function. For each
228         * bit in the original address, we use the first bit of the resulting
229         * encrypted output as part of an XOR mask */
230        EVP_EncryptUpdate(&this->ctx, (unsigned char *)rin_output, &outl, 
231                (unsigned char *)rin_input, 16);
232
233        /* Put the first bit of the output into the right slot of our mask */
234        res |= (((uint32_t)rin_output[0]) >> 7) << (31 - pos);
235
236    }
237    return res;
238
239}
240
241uint64_t CryptoAnon::encrypt64Bits(uint64_t orig) {
242
243    /* See encrypt32Bits for more explanation of how this works */
244    uint8_t rin_output[32];
245    uint8_t rin_input[16];
246    uint64_t first8pad;
247    int outl = 32;
248    uint64_t result = 0;
249
250    memcpy(rin_input, this->padding, 16);
251    memcpy(&first8pad, this->padding, 8);
252
253    for (int pos = 0; pos < 64; pos ++) {
254        uint64_t input;
255
256        if (pos == 0) {
257            input = first8pad;
258        } else {
259            input = ((orig >> (64 - pos)) << (64 - pos)) |
260                    ((first8pad << pos) >> pos);
261        }
262
263        memcpy(rin_input, &input, 8);
264
265        EVP_EncryptUpdate(&this->ctx, (unsigned char *)rin_output, &outl,
266                (unsigned char *)rin_input, 16);
267
268        result |= ((((uint64_t)rin_output[0]) >> 7) << (63 - pos));
269    }
270
271    return result;
272}
273
274#endif
275
276// vim: set sw=4 tabstop=4 softtabstop=4 expandtab :
Note: See TracBrowser for help on using the repository browser.