File Coverage

blib/lib/IP/Anonymous.pm
Criterion Covered Total %
statement 51 53 96.2
branch 1 2 50.0
condition n/a
subroutine 8 8 100.0
pod 2 2 100.0
total 62 65 95.3


line stmt bran cond sub pod time code
1             # IP::Anonymous - Perl port of Crypto-PAn to provide anonymous IP addresses
2             #
3             # Copyright (c) 2005 John Kristoff . All rights
4             # reserved. This program is free software; you can redistribute it and/or
5             # modify it under the same terms as Perl itself.
6              
7             package IP::Anonymous;
8             $VERSION = '0.04';
9             require 5.001;
10              
11             # base extensions and modules
12 1     1   8694 use strict; # force us to code defensively
  1         3  
  1         41  
13 1     1   6 use warnings; # do not let laziness go unnoticed
  1         2  
  1         42  
14 1     1   5 use vars qw($VERSION); # package scope global vars
  1         7  
  1         49  
15 1     1   5 use Carp; # make errors the caller's problem
  1         2  
  1         147  
16 1     1   1103 use Socket; # for convenient dotted quad handling routines
  1         5898  
  1         614  
17              
18             # additional modules
19 1     1   1433 use Crypt::Rijndael; # the Rijndael crypto magic
  1         2705  
  1         722  
20              
21             # module scope vars
22             my $m_pad; # 2nd 128 bits of user key used for secret padding
23             my $ecb; # electronic codebook mode (default) object
24             my $first4bytes_pad; # 1st 4 bytes of secret pad in "network" order
25              
26             # initialize
27             sub new {
28 2     2 1 663 my $package = shift;
29 2         7 my @key = @_; # expected key is 32 8-bit unsigned ints
30 2         3 my $m_key; # 1st 128 bits of user key used for cipher
31              
32             # 1st 128 bits of key used as secret key for Rijndael cipher
33 2         10 $m_key = pack("C16", @key[0..15]);
34             # 2nd 128 bits of key used for secret padding
35 2         8 $m_pad = pack("C16", @key[16..31]);
36              
37             # init the key
38 2         27 $ecb = new Crypt::Rijndael $m_key;
39             # encrypt the 128-bit secret pad
40 2         16 $m_pad = $ecb->encrypt($m_pad);
41              
42             # first four bytes of secret pad in "network" (big-endian) order
43 2         6 $first4bytes_pad = unpack("N", $m_pad);
44              
45 2         9 return bless({}, $package);
46             }
47              
48             # generate a bit using the Rijndael cipher for each of the 32 bit address
49             # msb bits taken from original address, remaining bits are from m_pad
50             sub anonymize {
51 10     10 1 1337 my $package = shift;
52 10         14 my $address = shift; # expect dotted quad string
53 10         11 my $first4bytes_input; # used to handle the byte ordering problem
54 10         15 my @rin_input = (); # psuedorandom Rijndael cipher used each round
55 10         11 my $rin_output; # encrypted byte result at each round
56 10         11 my $result = 0; # initialize psuedorandom one time pad
57              
58             # rudimentary check for correctly formatted dotted quad
59 10 50       58 if($address !~ /^\d{1,3}(?:\.\d{1,3}){3}$/) {
60 0         0 croak("ERROR [".__LINE__."]: invalid IP address format\n");
61 0         0 return;
62             }
63              
64             # convert dotted quad to long in "network" (big-endian) order
65 10         53 $address = unpack("N", pack("C4", split /\./, $address));
66              
67             # Rijndael cipher used to obtain each of the 32 anonymized bits
68 10         45 @rin_input = unpack("C16", $m_pad);
69              
70             # init input with encrypted pad
71 10         16 $rin_input[0] = ($first4bytes_pad >> 24);
72             # mask off excess bits for 64-bit systems in left shift
73 10         16 $rin_input[1] = (($first4bytes_pad << 8 & 0xffffffff) >> 24);
74 10         12 $rin_input[2] = (($first4bytes_pad << 16 & 0xffffffff) >> 24);
75 10         14 $rin_input[3] = (($first4bytes_pad << 24 & 0xffffffff) >> 24);
76              
77             # get an 8-bit byte
78 10         55 $rin_output = unpack("C", $ecb->encrypt(pack("C16", @rin_input)));
79             # only the first bit of rin_output is used for each round
80 10         15 $result |= ($rin_output >> 7) << 31;
81              
82             # loop through remaining 31 bits
83 10         29 for (my $position=1; $position <= 31; $position++) {
84 310         459 $first4bytes_input = (($address >> (32-$position)) <<
85             (32-$position)) |
86             # mask off excess bits for 64-bit systems
87             (($first4bytes_pad << $position & 0xffffffff) >>
88             $position);
89              
90 310         325 $rin_input[0] = ($first4bytes_input >> 24);
91             # mask off excess bits for 64-bit systems in left shift
92 310         380 $rin_input[1] = (($first4bytes_input << 8 & 0xffffffff) >> 24);
93 310         372 $rin_input[2] = (($first4bytes_input << 16 & 0xffffffff) >> 24);
94 310         336 $rin_input[3] = (($first4bytes_input << 24 & 0xffffffff) >> 24);
95              
96             # get an 8-bit byte
97 310         1183 $rin_output = unpack("C", $ecb->encrypt(pack("C16", @rin_input)));
98             # only the first bit of rin_output is used for each round
99 310         909 $result |= ($rin_output >> 7) << (31-$position);
100             }
101             # return anonymized, prefix-preserved address as a dotted quad string
102 10         89 return inet_ntoa(pack("N", $result ^ $address))
103             }
104              
105             1;
106              
107             __END__