forked from FFM/pycryptopan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cryptopan.py
executable file
·85 lines (63 loc) · 2.78 KB
/
cryptopan.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/env ipython3
# pycryptopan - a python module implementing the CryptoPAn algorithm
# Copyright (C) 2013 - the CONFINE project
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from functools import reduce
# from pycrypto module
from Crypto.Cipher.AES import new as AES
# from Crypto import Random
class CryptoPanError(Exception):
def __init__(self, value):
self.value=value
def __str__(self):
return repr(self.value)
class CryptoPan():
def __init__(self, key):
if len(key)!=32:
raise CryptoPanError("Key must be a 32 byte long string")
self.aes=AES(key[0:16])
self.pad=self.aes.encrypt(key[16:32])
f4=self.pad[0:4]
# Python 2 requires explicit conversion to ints
if isinstance(f4, str):
f4=[ord(x) for x in f4]
f4bp=self.toint(f4)
self.masks=[(mask, f4bp & (~ mask)) for mask in (0xFFFFFFFF >> (32 - p) << (32 - p) for p in range(0, 32))]
def toint(self, array):
return array[0] << 24 | array[1] <<16 | array[2] << 8 | array[3]
def toarray(self, n):
for i in range(3, -1, -1):
yield (n >> (i * 8)) & 0xFF
def anonymize(self, ip):
result=0
address=[int(x) for x in ip.split(".")]
if len(address)!=4:
raise CryptoPanError("Invalid IPv4 Address")
address=self.toint(address)
def calc(a):
""" calculate the first bit for Crypto-PAN"""
a_array = self.toarray(a)
# Python 2 requires converting ints to chars one at a time
if isinstance(self.pad, str):
inp="".join((chr(x) for x in a_array))
else:
inp=bytes(a_array)
inp+=self.pad[4:]
rin_output=self.aes.encrypt(inp)
out=rin_output[0]
# Python 2 requires explicit conversion to int
if isinstance(out, str):
out=ord(out)
return out >> 7
addresses=((address & mask[0]) | mask[1] for mask in self.masks)
result=reduce(lambda x, y: x << 1 | y, (calc(a) for a in addresses), 0)
return ".".join(["%s" % x for x in self.toarray(result ^ address)])