将C枚举位域转换为Python
在查看kismet的源代码时,发现了packet_ieee80211.h这个部分。
enum crypt_type {
crypt_none = 0,
crypt_unknown = 1,
crypt_wep = (1 << 1),
crypt_layer3 = (1 << 2),
// Derived from WPA headers
crypt_wep40 = (1 << 3),
crypt_wep104 = (1 << 4),
crypt_tkip = (1 << 5),
crypt_wpa = (1 << 6),
crypt_psk = (1 << 7),
crypt_aes_ocb = (1 << 8),
crypt_aes_ccm = (1 << 9),
//WPA Migration Mode
crypt_wpa_migmode = (1 << 19),
// Derived from data traffic
crypt_leap = (1 << 10),
crypt_ttls = (1 << 11),
crypt_tls = (1 << 12),
crypt_peap = (1 << 13),
crypt_isakmp = (1 << 14),
crypt_pptp = (1 << 15),
crypt_fortress = (1 << 16),
crypt_keyguard = (1 << 17),
crypt_unknown_nonwep = (1 << 18),
};
我理解这是在移动位,但也就仅此而已。假设我有一个整数706,我该如何将这个数字拆分成上面定义的cryptset,也就是说,我怎么能提取出706中使用了哪些加密方式,特别是用Python来实现。
谢谢。
2 个回答
首先,你需要明白的是,这个枚举(enum)定义了一系列的位掩码。在这个例子中,每一个枚举值在二进制中都只包含一个1
。比如说,
crypt_wep = (1 << 1) = 0b10
crypt_wpa = (1 << 6) = 0b1000000
接下来,使用位移运算符是一种简单的方式来表示'我想要第n+1个二进制位作为标志'。
这样,我们就可以将这些值进行按位或
运算,得到一个魔法数字,这个数字独特地描述了这些加密值的组合,作为位标志。要测试一个魔法数字是否包含某个值,我们只需将它与我们想要测试的值进行按位与
运算。
magic_number = crypt_wep | crypt_wpa
has_wep = (magic_number & crypt_wep) == crypt_wep
has_wpa = (magic_number & crypt_wpa) == crypt_wpa
has_wep
和has_wpa
只有在magic_number
包含这些位标志时才会是true
。
接下来,我们来看一下数字706
,它的二进制表示是0b1011000010
。我们可以从中看到,它一定是由crypt_wep
、crypt_wpa
、crypt_psk
和crypt_aes_ccm
构成的,因为这些值的正确位被设置了。
那么,如何在Python中实现呢?如果你使用的是Python 3.4或更高版本,Python也有枚举,就像C/C++一样。所以你可以在Python中创建相同的枚举表,并应用相同的按位测试来确定你的魔法数字代表什么。如果你使用的Python版本没有枚举,你可以简单地定义一个包含一些静态常量的类,以达到相同的效果(并构建一个方法来测试一个魔法数字包含的加密集合)。这样的类可能看起来像这样:
class CryptKeys(object):
crypt_masks = {
'crypt_unknown':1,
....
'crypt_unknown_nonwep': (1 << 18)
}
@classmethod
def find_crypts(cls, magic_number):
if magic_number == 0:
return ['crypt_none']
else:
return [name for name, mask in cls.crypt_masks.items() if magic_number & mask == mask]
Aruisdante的回答非常好,我只是想补充一下,如果你需要使用Python 3.4之前的版本,可以在PyPI上找到一个回溯版本,具体可以查看这个链接:回溯版本。
from enum import IntEnum
class Crypt(IntEnum):
none = 0
unknown = 1
wep = (1 << 1)
layer3 = (1 << 2)
# Derived from WPA headers
wep40 = (1 << 3)
wep104 = (1 << 4)
tkip = (1 << 5)
wpa = (1 << 6)
psk = (1 << 7)
aes_ocb = (1 << 8)
aes_ccm = (1 << 9)
# WPA Migration Mode
wpa_migmode = (1 << 19)
# Derived from data traffic
leap = (1 << 10)
ttls = (1 << 11)
tls = (1 << 12)
peap = (1 << 13)
isakmp = (1 << 14)
pptp = (1 << 15)
fortress = (1 << 16)
keyguard = (1 << 17)
unknown_nonwep = (1 << 18)
@classmethod
def find_crypts(cls, magic_number):
crypts = []
for mask in cls:
if magic_number & mask == mask:
crypts.append(mask)
if len(crypts) > 1:
# remove false positive of none
crypts = crypts[1:]
return crypts
print Crypt.find_crypts(0)
[<Crypt.none: 0>]
print Crypt.find_crypts(706)
[<Crypt.wep: 2>, <Crypt.wpa: 64>, <Crypt.psk: 128>, <Crypt.aes_ccm: 512>]